diff --git a/packages/kbn-interpreter/package.json b/packages/kbn-interpreter/package.json index 1648e66cdb300a..1a636ad8c61c47 100644 --- a/packages/kbn-interpreter/package.json +++ b/packages/kbn-interpreter/package.json @@ -24,6 +24,7 @@ "babel-plugin-transform-runtime": "^6.23.0", "babel-polyfill": "6.20.0", "css-loader": "1.0.0", + "copy-webpack-plugin": "^4.6.0", "del": "^3.0.0", "getopts": "^2.2.3", "pegjs": "0.9.0", diff --git a/packages/kbn-interpreter/src/plugin/functions/browser/register.js b/packages/kbn-interpreter/src/plugin/functions/browser/register.js new file mode 100644 index 00000000000000..4d9d0304a9b431 --- /dev/null +++ b/packages/kbn-interpreter/src/plugin/functions/browser/register.js @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import '../common/register'; diff --git a/packages/kbn-interpreter/src/server/server_registries.js b/packages/kbn-interpreter/src/server/server_registries.js index 90dba7b82cff74..2a456bee7de07f 100644 --- a/packages/kbn-interpreter/src/server/server_registries.js +++ b/packages/kbn-interpreter/src/server/server_registries.js @@ -48,8 +48,6 @@ export const populateServerRegistries = types => { const remainingTypes = types; const populatedTypes = {}; - const globalKeys = Object.keys(global); - const loadType = () => { const type = remainingTypes.pop(); getPluginPaths(type).then(paths => { @@ -60,11 +58,7 @@ export const populateServerRegistries = types => { require(path); // eslint-disable-line import/no-dynamic-require }); - Object.keys(global).forEach(key => { - if (!globalKeys.includes(key)) { - delete global[key]; - } - }); + delete global.canvas; populatedTypes[type] = registries[type]; if (remainingTypes.length) loadType(); diff --git a/packages/kbn-interpreter/tasks/build/__fixtures__/sample.js b/packages/kbn-interpreter/tasks/build/__fixtures__/sample.js new file mode 100644 index 00000000000000..f831545743f106 --- /dev/null +++ b/packages/kbn-interpreter/tasks/build/__fixtures__/sample.js @@ -0,0 +1,3 @@ +/* eslint-disable */ +import util from 'util'; +console.log(util.format('hello world')); diff --git a/packages/kbn-interpreter/tasks/build/server_code_transformer.js b/packages/kbn-interpreter/tasks/build/server_code_transformer.js new file mode 100644 index 00000000000000..5db4dc13640cb1 --- /dev/null +++ b/packages/kbn-interpreter/tasks/build/server_code_transformer.js @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const { extname } = require('path'); + +const { transform } = require('babel-core'); + +exports.createServerCodeTransformer = (sourceMaps) => { + return (content, path) => { + switch (extname(path)) { + case '.js': + const { code = '' } = transform(content.toString('utf8'), { + filename: path, + ast: false, + code: true, + sourceMaps: sourceMaps ? 'inline' : false, + babelrc: false, + presets: [require.resolve('@kbn/babel-preset/webpack_preset')], + }); + + return code; + + default: + return content.toString('utf8'); + } + }; +}; diff --git a/packages/kbn-interpreter/tasks/build/server_code_transformer.test.js b/packages/kbn-interpreter/tasks/build/server_code_transformer.test.js new file mode 100644 index 00000000000000..01dc9323352ae4 --- /dev/null +++ b/packages/kbn-interpreter/tasks/build/server_code_transformer.test.js @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { readFileSync } from 'fs'; +import { resolve } from 'path'; +import { createServerCodeTransformer } from './server_code_transformer'; + +const JS_FIXTURE_PATH = resolve(__dirname, '__fixtures__/sample.js'); +const JS_FIXTURE = readFileSync(JS_FIXTURE_PATH); + +describe('js support', () => { + it('transpiles js file', () => { + const transformer = createServerCodeTransformer(); + expect(transformer(JS_FIXTURE, JS_FIXTURE_PATH)).toMatchInlineSnapshot(` +"'use strict'; + +var _util = require('util'); + +var _util2 = _interopRequireDefault(_util); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +console.log(_util2.default.format('hello world')); /* eslint-disable */" +`); + }); + + it('throws errors for js syntax errors', () => { + const transformer = createServerCodeTransformer(); + expect(() => transformer(Buffer.from(`export default 'foo`), JS_FIXTURE_PATH)).toThrowError( + /Unterminated string constant/ + ); + }); +}); diff --git a/packages/kbn-interpreter/tasks/build/webpack.config.js b/packages/kbn-interpreter/tasks/build/webpack.config.js index 71e0cfd733da05..5d5afc92a24967 100644 --- a/packages/kbn-interpreter/tasks/build/webpack.config.js +++ b/packages/kbn-interpreter/tasks/build/webpack.config.js @@ -18,6 +18,10 @@ */ const { resolve } = require('path'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); + +const { createServerCodeTransformer } = require('./server_code_transformer'); + const { PLUGIN_SOURCE_DIR, PLUGIN_BUILD_DIR, @@ -31,7 +35,7 @@ module.exports = function ({ sourceMaps }, { watch }) { mode: 'none', entry: { 'types/all': resolve(PLUGIN_SOURCE_DIR, 'types/register.js'), - 'functions/common/all': resolve(PLUGIN_SOURCE_DIR, 'functions/common/register.js'), + 'functions/browser/all': resolve(PLUGIN_SOURCE_DIR, 'functions/browser/register.js'), }, // there were problems with the node and web targets since this code is actually @@ -95,6 +99,15 @@ module.exports = function ({ sourceMaps }, { watch }) { stats: 'errors-only', plugins: [ + new CopyWebpackPlugin([ + { + from: resolve(PLUGIN_SOURCE_DIR, 'functions/common'), + to: resolve(PLUGIN_BUILD_DIR, 'functions/common'), + ignore: '**/__tests__/**', + transform: createServerCodeTransformer(sourceMaps) + }, + ]), + function LoaderFailHandlerPlugin() { if (!watch) { return; diff --git a/src/dev/mocha/run_mocha_cli.js b/src/dev/mocha/run_mocha_cli.js index df146cf1fc9bcb..46676f9365ff60 100644 --- a/src/dev/mocha/run_mocha_cli.js +++ b/src/dev/mocha/run_mocha_cli.js @@ -42,6 +42,8 @@ export function runMochaCli() { // check that we aren't leaking any globals process.argv.push('--check-leaks'); + // prevent globals injected from canvas plugins from triggering leak check + process.argv.push('--globals', 'core,regeneratorRuntime,_'); // ensure that mocha requires the setup_node_env script process.argv.push('--require', require.resolve('../../setup_node_env')); diff --git a/src/legacy/core_plugins/interpreter/public/load_browser_plugins.js b/src/legacy/core_plugins/interpreter/public/load_browser_plugins.js index de550f5c6a3511..a8c43ceaaebb49 100644 --- a/src/legacy/core_plugins/interpreter/public/load_browser_plugins.js +++ b/src/legacy/core_plugins/interpreter/public/load_browser_plugins.js @@ -22,7 +22,6 @@ import { populateBrowserRegistries } from '@kbn/interpreter/public'; import { typesRegistry, functionsRegistry } from '@kbn/interpreter/common'; const types = { - commonFunctions: functionsRegistry, browserFunctions: functionsRegistry, types: typesRegistry }; diff --git a/src/setup_node_env/babel_register/register.js b/src/setup_node_env/babel_register/register.js index 2dd5850cfa9fbf..f0898b245fb0e7 100644 --- a/src/setup_node_env/babel_register/register.js +++ b/src/setup_node_env/babel_register/register.js @@ -41,9 +41,8 @@ var ignore = [ // is `x-pack` and `b` is not `node_modules` /\/node_modules\/(?!x-pack\/(?!node_modules)([^\/]+))([^\/]+\/[^\/]+)/, - // ignore paths matching `/canvas/canvas_plugin/{a}/{b}` unless - // `a` is `functions` and `b` is `server` - /\/canvas\/canvas_plugin\/(?!functions\/server)([^\/]+\/[^\/]+)/, + // ignore paths matching `/canvas/canvas_plugin/` + /\/canvas\/canvas_plugin\//, ]; if (global.__BUILT_WITH_BABEL__) { diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.js b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.js index 3a5fa0c5733161..61fd7d94e8d01a 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.js +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.js @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import { functions as commonFunctions } from '../common'; import { browser } from './browser'; import { location } from './location'; import { urlparam } from './urlparam'; import { markdown } from './markdown'; -export const functions = [browser, location, urlparam, markdown]; +export const functions = [browser, location, urlparam, markdown, ...commonFunctions]; diff --git a/x-pack/plugins/canvas/tasks/helpers/webpack.plugins.js b/x-pack/plugins/canvas/tasks/helpers/webpack.plugins.js index 8d78dc18fb3678..e2385c87b546c6 100644 --- a/x-pack/plugins/canvas/tasks/helpers/webpack.plugins.js +++ b/x-pack/plugins/canvas/tasks/helpers/webpack.plugins.js @@ -6,6 +6,9 @@ const path = require('path'); const CopyWebpackPlugin = require('copy-webpack-plugin'); +const { + createServerCodeTransformer, +} = require('@kbn/interpreter/tasks/build/server_code_transformer'); const sourceDir = path.resolve(__dirname, '../../canvas_plugin_src'); const buildDir = path.resolve(__dirname, '../../canvas_plugin'); @@ -25,7 +28,6 @@ export function getWebpackConfig({ devtool, watch } = {}) { 'uis/datasources/all': path.join(sourceDir, 'uis/datasources/register.js'), 'uis/arguments/all': path.join(sourceDir, 'uis/arguments/register.js'), 'functions/browser/all': path.join(sourceDir, 'functions/browser/register.js'), - 'functions/common/all': path.join(sourceDir, 'functions/common/register.js'), 'templates/all': path.join(sourceDir, 'templates/register.js'), 'uis/tags/all': path.join(sourceDir, 'uis/tags/register.js'), }, @@ -74,8 +76,21 @@ export function getWebpackConfig({ devtool, watch } = {}) { }, new CopyWebpackPlugin([ { - from: `${sourceDir}/functions/server/`, - to: `${buildDir}/functions/server/`, + from: path.resolve(sourceDir, 'functions/server'), + to: path.resolve(buildDir, 'functions/server'), + transform: createServerCodeTransformer(!!devtool), + ignore: '**/__tests__/**', + }, + { + from: path.resolve(sourceDir, 'functions/common'), + to: path.resolve(buildDir, 'functions/common'), + transform: createServerCodeTransformer(!!devtool), + ignore: '**/__tests__/**', + }, + { + from: path.resolve(sourceDir, 'lib'), + to: path.resolve(buildDir, 'lib'), + transform: createServerCodeTransformer(!!devtool), ignore: '**/__tests__/**', }, ]), diff --git a/yarn.lock b/yarn.lock index 7bf434e10087cc..41e63d6ecfede0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5981,6 +5981,20 @@ copy-webpack-plugin@^4.5.2: p-limit "^1.0.0" serialize-javascript "^1.4.0" +copy-webpack-plugin@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" + integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== + dependencies: + cacache "^10.0.4" + find-cache-dir "^1.0.0" + globby "^7.1.1" + is-glob "^4.0.0" + loader-utils "^1.1.0" + minimatch "^3.0.4" + p-limit "^1.0.0" + serialize-javascript "^1.4.0" + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"