Files
cypress/packages/server/lib/plugins/preprocessor.coffee
Kukhyeon Heo e22b362d4c Out-of-the-box TypeScript Support (#5906)
* Out-of-the-box TypeScript support for plugins

* Out-of-the-box TypeScript Support for tests.

* Fix server unit tests.

* Don't use bundled typescript.

* Added esModuleInterop option.

* Fixed unit tests.

* Added simple_tsify to integration test.

* Added integration tests for ts spec files.

* simple_tsify to ignore transpiling json files.

* transpile on flush.

* Fix lint failure.

* Added error message.

* Add error message for restart test runner for support file.

* Added JSDoc comment.

* Remove preset-typescript.

* Fix integration test failure.

* Fix type errors.

* Add e2e test for typescript

* Fix lint error.

* Add plugin support and e2e test.

* Fix server unit test failures.

* Update snapshots.

* Migrate typescript compilation code to browserify-preprocessor

* Remove unnecessary files and test.

They're tested in preprocessor.

* Fix test failures.

* Update @types/react.

* Update yarn.lock.

* Clear name: registerTS -> tsRegistered.

* Clarify why tsRegistered = true exists.

* Add working examples for support and plugins.

* Move TypeScript tests to its own file.
2020-04-13 21:39:13 +06:30

131 lines
3.4 KiB
CoffeeScript

_ = require("lodash")
EE = require("events")
path = require("path")
debug = require("debug")("cypress:server:preprocessor")
Promise = require("bluebird")
appData = require("../util/app_data")
cwd = require("../cwd")
plugins = require("../plugins")
savedState = require("../saved_state")
resolve = require('./resolve')
errorMessage = (err = {}) ->
(err.stack ? err.annotated ? err.message ? err.toString())
## strip out stack noise from parser like
## at Parser.pp$5.raise (/path/to/node_modules/babylon/lib/index.js:4215:13)
.replace(/\n\s*at.*/g, "")
.replace(/From previous event:\n?/g, "")
clientSideError = (err) ->
console.log(err.message)
err = errorMessage(err)
"""
(function () {
Cypress.action("spec:script:error", {
type: "BUNDLE_ERROR",
error: #{JSON.stringify(err)}
})
}())
"""
getOutputPath = (config, filePath) ->
appData.projectsPath(savedState.toHashName(config.projectRoot), "bundles", filePath)
baseEmitter = new EE()
fileObjects = {}
fileProcessors = {}
setDefaultPreprocessor = (config) ->
debug("set default preprocessor")
browserify = require("@cypress/browserify-preprocessor")
tsPath = resolve.typescript(config)
plugins.register("file:preprocessor", browserify({
typescript: tsPath
}))
plugins.registerHandler (ipc) ->
ipc.on "preprocessor:rerun", (filePath) ->
debug("ipc preprocessor:rerun event")
baseEmitter.emit("file:updated", filePath)
baseEmitter.on "close", (filePath) ->
debug("base emitter plugin close event")
ipc.send("preprocessor:close", filePath)
module.exports = {
errorMessage
clientSideError
emitter: baseEmitter
getFile: (filePath, config) ->
filePath = path.resolve(config.projectRoot, filePath)
debug("getFile #{filePath}")
if not fileObject = fileObjects[filePath]
## we should be watching the file if we are NOT
## in a text terminal aka cypress run
## TODO: rename this to config.isRunMode
## vs config.isInterativeMode
shouldWatch = not config.isTextTerminal
baseFilePath = filePath
.replace(config.projectRoot, "")
.replace(config.integrationFolder, "")
fileObject = fileObjects[filePath] = _.extend(new EE(), {
filePath,
shouldWatch,
outputPath: getOutputPath(config, baseFilePath)
})
fileObject.on "rerun", ->
debug("file object rerun event")
baseEmitter.emit("file:updated", filePath)
baseEmitter.once "close", ->
debug("base emitter native close event")
fileObject.emit("close")
if not plugins.has("file:preprocessor")
setDefaultPreprocessor(config)
if config.isTextTerminal and fileProcessor = fileProcessors[filePath]
debug("headless and already processed")
return fileProcessor
preprocessor = fileProcessors[filePath] = Promise.try ->
plugins.execute("file:preprocessor", fileObject)
return preprocessor
removeFile: (filePath, config) ->
filePath = path.resolve(config.projectRoot, filePath)
return if not fileProcessors[filePath]
debug("removeFile #{filePath}")
baseEmitter.emit("close", filePath)
if fileObject = fileObjects[filePath]
fileObject.emit("close")
delete fileObjects[filePath]
delete fileProcessors[filePath]
close: ->
debug("close preprocessor")
fileObjects = {}
fileProcessors = {}
baseEmitter.emit("close")
baseEmitter.removeAllListeners()
}