From b4b8690d2751b54efaff95d09fa137c4b570f055 Mon Sep 17 00:00:00 2001 From: FND Date: Sun, 18 Feb 2018 16:06:13 +0100 Subject: [PATCH] added experimental TypeScript support caveats: * there's barely any abstraction here (cf. inline comment), so the only reason not to use TypeScript directly is module bundling via Rollup * this plugin is getting a little bloaty, but that seems inevitable unless we wanna make some separate TypeScript plugin fork it or include hooks for a `generateTranspiler` equivalent; YAGNI for now * more significantly, stuffing everything into the `js` config section seems a little risky WRT avoiding breaking changes in future evolution * the test's sample code seems pretty silly based on earlier efforts by @tillsc --- lib/bundle/config.js | 11 +++++- package.json | 1 + pkg/faucet-pipeline-typescript/package.json | 23 ++++++++++++ test/cli/run | 6 ++++ test/cli/test_typescript/expected.js | 39 +++++++++++++++++++++ test/cli/test_typescript/faucet.config.js | 14 ++++++++ test/cli/test_typescript/src/index.ts | 28 +++++++++++++++ test/cli/test_typescript/src/util.ts | 9 +++++ 8 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 pkg/faucet-pipeline-typescript/package.json create mode 100644 test/cli/test_typescript/expected.js create mode 100644 test/cli/test_typescript/faucet.config.js create mode 100644 test/cli/test_typescript/src/index.ts create mode 100644 test/cli/test_typescript/src/util.ts diff --git a/lib/bundle/config.js b/lib/bundle/config.js index 3fc2615..99b9d41 100644 --- a/lib/bundle/config.js +++ b/lib/bundle/config.js @@ -32,10 +32,12 @@ module.exports = generateConfig; // * `jsx.pragma` determines the function to use for JSX expressions // (e.g. `jsx: { pragma: "createElement" }`) // * additionally accepts the same options as `esnext` +// * `typescript`, if truthy, activates TypeScript transpilation - anything +// other than `true` will be passed through as TypeScript compiler options // * `compact`, if truthy, compresses the bundle's code while retaining the // source code's original structure function generateConfig({ extensions = [], // eslint-disable-next-line indent - externals, format, moduleName, esnext, jsx, compact }, { browsers }) { + externals, format, moduleName, esnext, jsx, typescript, compact }, { browsers }) { let plugins = []; if(esnext || jsx) { let transpiler = Object.assign({}, esnext, jsx); @@ -54,6 +56,13 @@ function generateConfig({ extensions = [], // eslint-disable-next-line indent extensions = ext.concat(extensions); plugins.push(plugin); } + if(typescript) { + let ts = requireOptional("rollup-plugin-typescript2", + "failed to activate TypeScript", "faucet-pipeline-typescript"); + extensions.push(".ts"); + // TODO: provide defaults and abstractions for low-level options? + plugins.push(typescript === true ? ts() : ts(typescript)); + } let resolve = { jsnext: true }; if(extensions.length) { diff --git a/package.json b/package.json index 5e52223..d8a5d30 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "eslint-config-fnd-jsx": "^1.1.0", "faucet-pipeline-esnext": "file:pkg/faucet-pipeline-esnext", "faucet-pipeline-jsx": "file:pkg/faucet-pipeline-jsx", + "faucet-pipeline-typescript": "file:pkg/faucet-pipeline-typescript", "json-diff": "^0.5.2", "mocha": "^5.0.1", "npm-run-all": "^4.1.2", diff --git a/pkg/faucet-pipeline-typescript/package.json b/pkg/faucet-pipeline-typescript/package.json new file mode 100644 index 0000000..649bbe2 --- /dev/null +++ b/pkg/faucet-pipeline-typescript/package.json @@ -0,0 +1,23 @@ +{ + "name": "faucet-pipeline-typescript", + "version": "1.0.0-beta.1", + "description": "TypeScript for faucet-pipeline", + "author": "FND", + "contributors": [ + "Till Schulte-Coerne " + ], + "license": "Apache-2.0", + "homepage": "https://github.com/faucet-pipeline/faucet-pipeline-js", + "repository": { + "type": "git", + "url": "https://github.com/faucet-pipeline/faucet-pipeline-js.git" + }, + "bugs": { + "url": "https://github.com/faucet-pipeline/faucet-pipeline-js/issues" + }, + "dependencies": { + "faucet-pipeline-js": "1.0.0-beta.1", + "rollup-plugin-typescript2": "^0.11.1", + "typescript": "^2.7.2" + } +} diff --git a/test/cli/run b/test/cli/run index d140bf2..34340b3 100755 --- a/test/cli/run +++ b/test/cli/run @@ -32,6 +32,12 @@ begin "$root/test_jsx" assert_identical "./dist/bundle.js" "./expected.js" end +begin "$root/test_typescript" + faucet + assert_identical "./dist/bundle.js" "./expected.js" + rm -r "./.rpt2_cache" +end + begin "$root/test_browserslist" faucet assert_identical "./dist/bundle.js" "./expected.js" diff --git a/test/cli/test_typescript/expected.js b/test/cli/test_typescript/expected.js new file mode 100644 index 0000000..94ebddc --- /dev/null +++ b/test/cli/test_typescript/expected.js @@ -0,0 +1,39 @@ +(function () { +'use strict'; + +if(typeof global === "undefined" && typeof window !== "undefined") { + window.global = window; +} + +var LogLevel; +(function (LogLevel) { + LogLevel[LogLevel["Debug"] = 0] = "Debug"; + LogLevel[LogLevel["Info"] = 1] = "Info"; + LogLevel[LogLevel["Critical"] = 2] = "Critical"; +})(LogLevel || (LogLevel = {})); +function log(level, msg) { + if (level === LogLevel.Critical) { + console.error(msg); + } + else { + console.log(msg); + } +} + +var generateArticle = function (params) { + var title = params.title, authors = params.authors; + if (typeof title !== "string") { + log(LogLevel.Debug, "auto-generating title"); + title = title.main + ": " + title.sub; + } + return title + "\n" + authors.join(", "); +}; +generateArticle({ + title: { + main: "Hello World", + sub: "sup" + }, + authors: ["foo", "bar"] +}); + +}()); diff --git a/test/cli/test_typescript/faucet.config.js b/test/cli/test_typescript/faucet.config.js new file mode 100644 index 0000000..bc3ed9f --- /dev/null +++ b/test/cli/test_typescript/faucet.config.js @@ -0,0 +1,14 @@ +"use strict"; + +let path = require("path"); + +module.exports = { + js: [{ + source: "./src/index.ts", + target: "./dist/bundle.js", + typescript: true + }], + plugins: { + js: path.resolve(__dirname, "../../..") + } +}; diff --git a/test/cli/test_typescript/src/index.ts b/test/cli/test_typescript/src/index.ts new file mode 100644 index 0000000..112128f --- /dev/null +++ b/test/cli/test_typescript/src/index.ts @@ -0,0 +1,28 @@ +import { log, LogLevel } from "./util"; + +interface ComplexTitle { + main: string; + sub: string; +} + +interface ArticleInterface { + title: string | ComplexTitle; + authors: string[]; +} + +let generateArticle = (params: ArticleInterface) => { + let { title, authors } = params; + if(typeof title !== "string") { + log(LogLevel.Debug, "auto-generating title"); + title = `${title.main}: ${title.sub}`; + } + return title + "\n" + authors.join(", "); +}; + +generateArticle({ + title: { + main: "Hello World", + sub: "sup" + }, + authors: ["foo", "bar"] +}); diff --git a/test/cli/test_typescript/src/util.ts b/test/cli/test_typescript/src/util.ts new file mode 100644 index 0000000..8987d96 --- /dev/null +++ b/test/cli/test_typescript/src/util.ts @@ -0,0 +1,9 @@ +export enum LogLevel { Debug, Info, Critical } + +export function log(level: LogLevel, msg: string) { + if(level === LogLevel.Critical) { + console.error(msg); + } else { + console.log(msg); + } +}