Pārlūkot izejas kodu

Convert to TypeScript

Alexandru Dima 5 gadi atpakaļ
vecāks
revīzija
0bd24b523b
15 mainītis faili ar 856 papildinājumiem un 693 dzēšanām
  1. 1 0
      .gitignore
  2. 1 0
      .npmignore
  3. 6 0
      .vscode/settings.json
  4. 0 34
      index.d.ts
  5. 0 218
      index.js
  6. 327 318
      package-lock.json
  7. 13 9
      package.json
  8. 89 43
      src/features.ts
  9. 261 0
      src/index.ts
  10. 109 53
      src/languages.ts
  11. 3 3
      src/loaders/include.ts
  12. 18 14
      src/plugins/AddWorkerEntryPointPlugin.ts
  13. 12 0
      src/types.ts
  14. 1 1
      test/webpack.config.js
  15. 15 0
      tsconfig.json

+ 1 - 0
.gitignore

@@ -1,3 +1,4 @@
 /node_modules/
 /test/node_modules/
 /test/dist/*.js
+/out/

+ 1 - 0
.npmignore

@@ -1 +1,2 @@
+/src/
 /test/

+ 6 - 0
.vscode/settings.json

@@ -0,0 +1,6 @@
+{
+  "files.trimTrailingWhitespace": true,
+  "files.insertFinalNewline": true,
+  "editor.tabSize": 2,
+  "editor.insertSpaces": true
+}

+ 0 - 34
index.d.ts

@@ -1,34 +0,0 @@
-import { Plugin } from 'webpack'
-
-interface IMonacoEditorWebpackPluginOpts {
-    /**
-     * Include only a subset of the languages supported.
-     */
-    languages?: string[];
-
-    /**
-     * Include only a subset of the editor features.
-     * Use e.g. '!contextmenu' to exclude a certain feature.
-     */
-    features?: string[];
-
-    /**
-     * Specify a filename template to use for generated files.
-     * Use e.g. '[name].worker.[contenthash].js' to include content-based hashes.
-     */
-    filename?: string;
-
-    /**
-     * Override the public path from which files generated by this plugin will be served.
-     * This wins out over Webpack's dynamic runtime path and can be useful to avoid attempting to load workers cross-
-     * origin when using a CDN for other static resources.
-     * Use e.g. '/' if you want to load your resources from the current origin.
-     */
-    publicPath?: string;
-}
-
-declare class MonacoEditorWebpackPlugin extends Plugin {
-    constructor(opts?: IMonacoEditorWebpackPluginOpts)
-}
-
-export = MonacoEditorWebpackPlugin

+ 0 - 218
index.js

@@ -1,218 +0,0 @@
-const path = require('path');
-const webpack = require('webpack');
-const loaderUtils = require('loader-utils');
-const fs = require('fs');
-
-const AddWorkerEntryPointPlugin = require('./plugins/AddWorkerEntryPointPlugin');
-const INCLUDE_LOADER_PATH = require.resolve('./loaders/include');
-
-const EDITOR_MODULE = {
-  label: 'editorWorkerService',
-  entry: undefined,
-  worker: {
-    id: 'vs/editor/editor',
-    entry: 'vs/editor/editor.worker',
-    fallback: undefined
-  },
-};
-const LANGUAGES = require('./languages');
-const FEATURES = require('./features');
-
-/**
- * Return a resolved path for a given Monaco file.
- */
-function resolveMonacoPath(filePath) {
-  return require.resolve(path.join('monaco-editor/esm', filePath));
-}
-
-/**
- * Return the interpolated final filename for a worker, respecting the file name template.
- */
-function getWorkerFilename(filename, entry) {
-  return loaderUtils.interpolateName({resourcePath: entry}, filename, {
-    content: fs.readFileSync(resolveMonacoPath(entry))
-  });
-}
-
-const languagesById = mapValues(LANGUAGES, (language, id) => mixin({ label: id }, language));
-const featuresById = mapValues(FEATURES, (feature, key) => mixin({ label: key }, feature))
-
-function getFeaturesIds(userFeatures, predefinedFeaturesById) {
-  function notContainedIn(arr) {
-    return (element) => arr.indexOf(element) === -1;
-  }
-
-  let featuresIds;
-
-  if (userFeatures.length) {
-    const excludedFeatures = userFeatures.filter(f => f[0] === '!').map(f => f.slice(1));
-    if (excludedFeatures.length) {
-      featuresIds = Object.keys(predefinedFeaturesById).filter(notContainedIn(excludedFeatures))
-    } else {
-      featuresIds = userFeatures;
-    }
-  } else {
-    featuresIds = Object.keys(predefinedFeaturesById);
-  }
-
-  return featuresIds;
-}
-
-class MonacoWebpackPlugin {
-  constructor(options = {}) {
-    const languages = options.languages || Object.keys(languagesById);
-    const features = getFeaturesIds(options.features || [], featuresById);
-    this.options = {
-      languages: languages.map((id) => languagesById[id]).filter(Boolean),
-      features: features.map(id => featuresById[id]).filter(Boolean),
-      filename: options.filename || "[name].worker.js",
-      publicPath: options.publicPath || '',
-    };
-  }
-
-  apply(compiler) {
-    const { languages, features, filename, publicPath } = this.options;
-    const compilationPublicPath = getCompilationPublicPath(compiler);
-    const modules = [EDITOR_MODULE].concat(languages).concat(features);
-    const workers = modules.map(
-      ({ label, worker }) => worker && (mixin({ label }, worker))
-    ).filter(Boolean);
-    const rules = createLoaderRules(languages, features, workers, filename, publicPath, compilationPublicPath);
-    const plugins = createPlugins(workers, filename);
-    addCompilerRules(compiler, rules);
-    addCompilerPlugins(compiler, plugins);
-  }
-}
-
-function addCompilerRules(compiler, rules) {
-  const compilerOptions = compiler.options;
-  const moduleOptions = compilerOptions.module || (compilerOptions.module = {});
-  moduleOptions.rules = (moduleOptions.rules || []).concat(rules);
-}
-
-function addCompilerPlugins(compiler, plugins) {
-  plugins.forEach((plugin) => plugin.apply(compiler));
-}
-
-function getCompilationPublicPath(compiler) {
-  return compiler.options.output && compiler.options.output.publicPath || '';
-}
-
-function createLoaderRules(languages, features, workers, filename, pluginPublicPath, compilationPublicPath) {
-  if (!languages.length && !features.length) { return []; }
-  const languagePaths = flatArr(languages.map(({ entry }) => entry).filter(Boolean));
-  const featurePaths = flatArr(features.map(({ entry }) => entry).filter(Boolean));
-  const workerPaths = fromPairs(workers.map(({ label, entry }) => [label, getWorkerFilename(filename, entry)]));
-  if (workerPaths['typescript']) {
-    // javascript shares the same worker
-    workerPaths['javascript'] = workerPaths['typescript'];
-  }
-  if (workerPaths['css']) {
-    // scss and less share the same worker
-    workerPaths['less'] = workerPaths['css'];
-    workerPaths['scss'] = workerPaths['css'];
-  }
-
-  if (workerPaths['html']) {
-    // handlebars, razor and html share the same worker
-    workerPaths['handlebars'] = workerPaths['html'];
-    workerPaths['razor'] = workerPaths['html'];
-  }
-
-  // Determine the public path from which to load worker JS files. In order of precedence:
-  // 1. Plugin-specific public path.
-  // 2. Dynamic runtime public path.
-  // 3. Compilation public path.
-  const pathPrefix = Boolean(pluginPublicPath)
-    ? JSON.stringify(pluginPublicPath)
-    : `typeof __webpack_public_path__ === 'string' ` +
-      `? __webpack_public_path__ ` +
-      `: ${JSON.stringify(compilationPublicPath)}`
-
-  const globals = {
-    'MonacoEnvironment': `(function (paths) {
-      function stripTrailingSlash(str) {
-        return str.replace(/\\/$/, '');
-      }
-      return {
-        getWorkerUrl: function (moduleId, label) {
-          var pathPrefix = ${pathPrefix};
-          return (pathPrefix ? stripTrailingSlash(pathPrefix) + '/' : '') + paths[label];
-        }
-      };
-    })(${JSON.stringify(workerPaths, null, 2)})`,
-  };
-  return [
-    {
-      test: /monaco-editor[/\\]esm[/\\]vs[/\\]editor[/\\]editor.(api|main).js/,
-      use: [
-        {
-          loader: INCLUDE_LOADER_PATH,
-          options: {
-            globals,
-            pre: featurePaths.map((importPath) => resolveMonacoPath(importPath)),
-            post: languagePaths.map((importPath) => resolveMonacoPath(importPath)),
-          },
-        },
-      ],
-    },
-  ];
-}
-
-function createPlugins(workers, filename) {
-  return (
-    []
-    .concat(uniqBy(workers, ({ id }) => id).map(({ id, entry }) =>
-      new AddWorkerEntryPointPlugin({
-        id,
-        entry: resolveMonacoPath(entry),
-        filename: getWorkerFilename(filename, entry),
-        plugins: [
-          new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
-        ],
-      })
-    ))
-  );
-}
-
-function flatArr(items) {
-  return items.reduce((acc, item) => {
-    if (Array.isArray(item)) {
-      return [].concat(acc).concat(item);
-    }
-    return [].concat(acc).concat([item]);
-  }, []);
-}
-
-function fromPairs(values) {
-  return values.reduce((acc, [key, value]) => Object.assign(acc, { [key]: value }), {});
-}
-
-function mapValues(object, iteratee) {
-  return Object.keys(object).reduce(
-    (acc, key) => Object.assign(acc, { [key]: iteratee(object[key], key) }),
-    {}
-  );
-}
-
-function uniqBy(items, iteratee) {
-  const keys = {};
-  return items.reduce((acc, item) => {
-    const key = iteratee(item);
-    if (key in keys) { return acc; }
-    keys[key] = true;
-    acc.push(item);
-    return acc;
-  }, []);
-}
-
-function mixin(dest, src) {
-  for (let prop in src) {
-    if (Object.hasOwnProperty.call(src, prop)) {
-      dest[prop] = src[prop];
-    }
-  }
-  return dest;
-}
-
-module.exports = MonacoWebpackPlugin;

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 327 - 318
package-lock.json


+ 13 - 9
package.json

@@ -2,10 +2,12 @@
   "name": "monaco-editor-webpack-plugin",
   "version": "1.7.0",
   "description": "A webpack plugin for the Monaco Editor",
-  "main": "index.js",
-  "typings": "./index.d.ts",
+  "main": "out/index.js",
+  "typings": "./out/index.d.ts",
   "scripts": {
-    "test": "node ./node_modules/webpack/bin/webpack.js --config test/webpack.config.js"
+    "test": "node ./node_modules/webpack/bin/webpack.js --config test/webpack.config.js",
+    "watch": "tsc -w -p tsconfig.json",
+    "prepublishOnly": "tsc -p tsconfig.json"
   },
   "repository": {
     "type": "git",
@@ -24,16 +26,18 @@
   },
   "homepage": "https://github.com/Microsoft/monaco-editor-webpack-plugin#readme",
   "peerDependencies": {
-    "webpack": "^4.5.0",
+    "webpack": "^4.41.3",
     "monaco-editor": "^0.17.0"
   },
   "devDependencies": {
-    "@types/webpack": "^4.4.19",
-    "css-loader": "^1.0.1",
+    "@types/loader-utils": "^1.1.3",
+    "@types/webpack": "^4.41.0",
+    "css-loader": "^3.4.0",
     "monaco-editor": "^0.17.0",
-    "style-loader": "^0.23.1",
-    "webpack": "^4.25.1",
-    "webpack-cli": "^3.1.2"
+    "style-loader": "^1.0.2",
+    "typescript": "^3.7.3",
+    "webpack": "^4.41.3",
+    "webpack-cli": "^3.3.10"
   },
   "dependencies": {
     "loader-utils": "^1.2.3"

+ 89 - 43
features.js → src/features.ts

@@ -1,128 +1,174 @@
-module.exports = {
-  accessibilityHelp: {
+import { IFeatureDefinition } from "./types";
+
+const featuresArr: IFeatureDefinition[] = [
+  {
+    label: 'accessibilityHelp',
     entry: 'vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp',
   },
-  bracketMatching: {
+  {
+    label: 'bracketMatching',
     entry: 'vs/editor/contrib/bracketMatching/bracketMatching',
   },
-  caretOperations: {
+  {
+    label: 'caretOperations',
     entry: 'vs/editor/contrib/caretOperations/caretOperations',
   },
-  clipboard: {
+  {
+    label: 'clipboard',
     entry: 'vs/editor/contrib/clipboard/clipboard',
   },
-  codeAction: {
+  {
+    label: 'codeAction',
     entry: 'vs/editor/contrib/codeAction/codeActionContributions',
   },
-  codelens: {
+  {
+    label: 'codelens',
     entry: 'vs/editor/contrib/codelens/codelensController',
   },
-  colorDetector: {
+  {
+    label: 'colorDetector',
     entry: 'vs/editor/contrib/colorPicker/colorDetector',
   },
-  comment: {
+  {
+    label: 'comment',
     entry: 'vs/editor/contrib/comment/comment',
   },
-  contextmenu: {
+  {
+    label: 'contextmenu',
     entry: 'vs/editor/contrib/contextmenu/contextmenu',
   },
-  coreCommands: {
+  {
+    label: 'coreCommands',
     entry: 'vs/editor/browser/controller/coreCommands',
   },
-  cursorUndo: {
+  {
+    label: 'cursorUndo',
     entry: 'vs/editor/contrib/cursorUndo/cursorUndo',
   },
-  dnd: {
+  {
+    label: 'dnd',
     entry: 'vs/editor/contrib/dnd/dnd',
   },
-  find: {
+  {
+    label: 'find',
     entry: 'vs/editor/contrib/find/findController',
   },
-  folding: {
+  {
+    label: 'folding',
     entry: 'vs/editor/contrib/folding/folding',
   },
-  fontZoom: {
+  {
+    label: 'fontZoom',
     entry: 'vs/editor/contrib/fontZoom/fontZoom',
   },
-  format: {
+  {
+    label: 'format',
     entry: 'vs/editor/contrib/format/formatActions',
   },
-  goToDefinitionCommands: {
+  {
+    label: 'goToDefinitionCommands',
     entry: 'vs/editor/contrib/goToDefinition/goToDefinitionCommands',
   },
-  goToDefinitionMouse: {
+  {
+    label: 'goToDefinitionMouse',
     entry: 'vs/editor/contrib/goToDefinition/goToDefinitionMouse',
   },
-  gotoError: {
+  {
+    label: 'gotoError',
     entry: 'vs/editor/contrib/gotoError/gotoError',
   },
-  gotoLine: {
+  {
+    label: 'gotoLine',
     entry: 'vs/editor/standalone/browser/quickOpen/gotoLine',
   },
-  hover: {
+  {
+    label: 'hover',
     entry: 'vs/editor/contrib/hover/hover',
   },
-  inPlaceReplace: {
+  {
+    label: 'inPlaceReplace',
     entry: 'vs/editor/contrib/inPlaceReplace/inPlaceReplace',
   },
-  inspectTokens: {
+  {
+    label: 'inspectTokens',
     entry: 'vs/editor/standalone/browser/inspectTokens/inspectTokens',
   },
-  iPadShowKeyboard: {
+  {
+    label: 'iPadShowKeyboard',
     entry: 'vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard',
   },
-  linesOperations: {
+  {
+    label: 'linesOperations',
     entry: 'vs/editor/contrib/linesOperations/linesOperations',
   },
-  links: {
+  {
+    label: 'links',
     entry: 'vs/editor/contrib/links/links',
   },
-  multicursor: {
+  {
+    label: 'multicursor',
     entry: 'vs/editor/contrib/multicursor/multicursor',
   },
-  parameterHints: {
+  {
+    label: 'parameterHints',
     entry: 'vs/editor/contrib/parameterHints/parameterHints',
   },
-  quickCommand: {
+  {
+    label: 'quickCommand',
     entry: 'vs/editor/standalone/browser/quickOpen/quickCommand',
   },
-  quickOutline: {
+  {
+    label: 'quickOutline',
     entry: 'vs/editor/standalone/browser/quickOpen/quickOutline',
   },
-  referenceSearch: {
+  {
+    label: 'referenceSearch',
     entry: [
       'vs/editor/contrib/referenceSearch/referenceSearch',
       'vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch',
     ],
   },
-  rename: {
+  {
+    label: 'rename',
     entry: 'vs/editor/contrib/rename/rename',
   },
-  smartSelect: {
+  {
+    label: 'smartSelect',
     entry: 'vs/editor/contrib/smartSelect/smartSelect',
   },
-  snippets: {
+  {
+    label: 'snippets',
     entry: 'vs/editor/contrib/snippet/snippetController2',
   },
-  suggest: {
+  {
+    label: 'suggest',
     entry: 'vs/editor/contrib/suggest/suggestController',
   },
-  toggleHighContrast: {
+  {
+    label: 'toggleHighContrast',
     entry: 'vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast',
   },
-  toggleTabFocusMode: {
+  {
+    label: 'toggleTabFocusMode',
     entry: 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode',
   },
-  transpose: {
+  {
+    label: 'transpose',
     entry: 'vs/editor/contrib/caretOperations/transpose',
   },
-  wordHighlighter: {
+  {
+    label: 'wordHighlighter',
     entry: 'vs/editor/contrib/wordHighlighter/wordHighlighter',
   },
-  wordOperations: {
+  {
+    label: 'wordOperations',
     entry: 'vs/editor/contrib/wordOperations/wordOperations',
   },
-  wordPartOperations: {
+  {
+    label: 'wordPartOperations',
     entry: 'vs/editor/contrib/wordPartOperations/wordPartOperations',
   },
-};
+];
+
+export const featuresById: { [feature: string]: IFeatureDefinition; } = {};
+featuresArr.forEach(feature => featuresById[feature.label] = feature);

+ 261 - 0
src/index.ts

@@ -0,0 +1,261 @@
+import * as path from 'path';
+import * as webpack from 'webpack';
+import * as loaderUtils from 'loader-utils';
+import * as fs from 'fs';
+import { AddWorkerEntryPointPlugin } from './plugins/AddWorkerEntryPointPlugin';
+import { languagesById } from './languages';
+import { featuresById } from './features';
+import { IFeatureDefinition } from './types';
+
+const INCLUDE_LOADER_PATH = require.resolve('./loaders/include');
+
+const EDITOR_MODULE: IFeatureDefinition = {
+  label: 'editorWorkerService',
+  entry: undefined,
+  worker: {
+    id: 'vs/editor/editor',
+    entry: 'vs/editor/editor.worker',
+    fallback: undefined
+  },
+};
+
+/**
+ * Return a resolved path for a given Monaco file.
+ */
+function resolveMonacoPath(filePath: string): string {
+  return require.resolve(path.join('monaco-editor/esm', filePath));
+}
+
+/**
+ * Return the interpolated final filename for a worker, respecting the file name template.
+ */
+function getWorkerFilename(filename: string, entry: string): string {
+  return loaderUtils.interpolateName(<any>{ resourcePath: entry }, filename, {
+    content: fs.readFileSync(resolveMonacoPath(entry))
+  });
+}
+
+function getFeaturesIds(userFeatures: string[]): string[] {
+  function notContainedIn(arr: string[]) {
+    return (element: string) => arr.indexOf(element) === -1;
+  }
+
+  let featuresIds: string[];
+
+  if (userFeatures.length) {
+    const excludedFeatures = userFeatures.filter(f => f[0] === '!').map(f => f.slice(1));
+    if (excludedFeatures.length) {
+      featuresIds = Object.keys(featuresById).filter(notContainedIn(excludedFeatures))
+    } else {
+      featuresIds = userFeatures;
+    }
+  } else {
+    featuresIds = Object.keys(featuresById);
+  }
+
+  return featuresIds;
+}
+
+interface IMonacoEditorWebpackPluginOpts {
+  /**
+   * Include only a subset of the languages supported.
+   */
+  languages?: string[];
+
+  /**
+   * Include only a subset of the editor features.
+   * Use e.g. '!contextmenu' to exclude a certain feature.
+   */
+  features?: string[];
+
+  /**
+   * Specify a filename template to use for generated files.
+   * Use e.g. '[name].worker.[contenthash].js' to include content-based hashes.
+   */
+  filename?: string;
+
+  /**
+   * Override the public path from which files generated by this plugin will be served.
+   * This wins out over Webpack's dynamic runtime path and can be useful to avoid attempting to load workers cross-
+   * origin when using a CDN for other static resources.
+   * Use e.g. '/' if you want to load your resources from the current origin.
+   */
+  publicPath?: string;
+}
+
+interface IInternalMonacoEditorWebpackPluginOpts {
+  languages: IFeatureDefinition[];
+  features: IFeatureDefinition[];
+  filename: string;
+  publicPath: string;
+}
+
+class MonacoEditorWebpackPlugin implements webpack.Plugin {
+
+  private readonly options: IInternalMonacoEditorWebpackPluginOpts;
+
+  constructor(options: IMonacoEditorWebpackPluginOpts = {}) {
+    const languages = options.languages || Object.keys(languagesById);
+    const features = getFeaturesIds(options.features || []);
+    this.options = {
+      languages: coalesce(languages.map(id => languagesById[id])),
+      features: coalesce(features.map(id => featuresById[id])),
+      filename: options.filename || "[name].worker.js",
+      publicPath: options.publicPath || '',
+    };
+  }
+
+  apply(compiler: webpack.Compiler): void {
+    const { languages, features, filename, publicPath } = this.options;
+    const compilationPublicPath = getCompilationPublicPath(compiler);
+    const modules = [EDITOR_MODULE].concat(languages).concat(features);
+    const workers: ILabeledWorkerDefinition[] = coalesce(modules.map(
+      ({ label, worker }) => worker && (mixin({ label }, worker))
+    ));
+    const rules = createLoaderRules(languages, features, workers, filename, publicPath, compilationPublicPath);
+    const plugins = createPlugins(workers, filename);
+    addCompilerRules(compiler, rules);
+    addCompilerPlugins(compiler, plugins);
+  }
+}
+
+interface ILabeledWorkerDefinition {
+  label: string;
+  id: string;
+  entry: string;
+  fallback: string | undefined;
+}
+
+function addCompilerRules(compiler: webpack.Compiler, rules: webpack.RuleSetRule[]): void {
+  const compilerOptions = compiler.options;
+  if (!compilerOptions.module) {
+    compilerOptions.module = { rules: rules };
+  } else {
+    const moduleOptions = compilerOptions.module;
+    moduleOptions.rules = (moduleOptions.rules || []).concat(rules);
+  }
+}
+
+function addCompilerPlugins(compiler: webpack.Compiler, plugins: webpack.Plugin[]) {
+  plugins.forEach((plugin) => plugin.apply(compiler));
+}
+
+function getCompilationPublicPath(compiler: webpack.Compiler): string {
+  return compiler.options.output && compiler.options.output.publicPath || '';
+}
+
+function createLoaderRules(languages: IFeatureDefinition[], features: IFeatureDefinition[], workers: ILabeledWorkerDefinition[], filename: string, pluginPublicPath: string, compilationPublicPath: string): webpack.RuleSetRule[] {
+  if (!languages.length && !features.length) {
+    return [];
+  }
+  const languagePaths = flatArr(coalesce(languages.map(({ entry }) => entry)));
+  const featurePaths = flatArr(coalesce(features.map(({ entry }) => entry)));
+  const workerPaths = fromPairs(workers.map(({ label, entry }) => [label, getWorkerFilename(filename, entry)]));
+  if (workerPaths['typescript']) {
+    // javascript shares the same worker
+    workerPaths['javascript'] = workerPaths['typescript'];
+  }
+  if (workerPaths['css']) {
+    // scss and less share the same worker
+    workerPaths['less'] = workerPaths['css'];
+    workerPaths['scss'] = workerPaths['css'];
+  }
+
+  if (workerPaths['html']) {
+    // handlebars, razor and html share the same worker
+    workerPaths['handlebars'] = workerPaths['html'];
+    workerPaths['razor'] = workerPaths['html'];
+  }
+
+  // Determine the public path from which to load worker JS files. In order of precedence:
+  // 1. Plugin-specific public path.
+  // 2. Dynamic runtime public path.
+  // 3. Compilation public path.
+  const pathPrefix = Boolean(pluginPublicPath)
+    ? JSON.stringify(pluginPublicPath)
+    : `typeof __webpack_public_path__ === 'string' ` +
+    `? __webpack_public_path__ ` +
+    `: ${JSON.stringify(compilationPublicPath)}`
+
+  const globals = {
+    'MonacoEnvironment': `(function (paths) {
+      function stripTrailingSlash(str) {
+        return str.replace(/\\/$/, '');
+      }
+      return {
+        getWorkerUrl: function (moduleId, label) {
+          var pathPrefix = ${pathPrefix};
+          return (pathPrefix ? stripTrailingSlash(pathPrefix) + '/' : '') + paths[label];
+        }
+      };
+    })(${JSON.stringify(workerPaths, null, 2)})`,
+  };
+  return [
+    {
+      test: /monaco-editor[/\\]esm[/\\]vs[/\\]editor[/\\]editor.(api|main).js/,
+      use: [{
+        loader: INCLUDE_LOADER_PATH,
+        options: {
+          globals,
+          pre: featurePaths.map((importPath) => resolveMonacoPath(importPath)),
+          post: languagePaths.map((importPath) => resolveMonacoPath(importPath)),
+        },
+      }],
+    },
+  ];
+}
+
+function createPlugins(workers: ILabeledWorkerDefinition[], filename: string): AddWorkerEntryPointPlugin[] {
+  return (
+    (<AddWorkerEntryPointPlugin[]>[])
+      .concat(uniqBy(workers, ({ id }) => id).map(({ id, entry }) =>
+        new AddWorkerEntryPointPlugin({
+          id,
+          entry: resolveMonacoPath(entry),
+          filename: getWorkerFilename(filename, entry),
+          plugins: [
+            new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
+          ],
+        })
+      ))
+  );
+}
+
+function flatArr<T>(items: (T | T[])[]): T[] {
+  return items.reduce((acc: T[], item: T | T[]) => {
+    if (Array.isArray(item)) {
+      return (<T[]>[]).concat(acc).concat(item);
+    }
+    return (<T[]>[]).concat(acc).concat([item]);
+  }, <T[]>[]);
+}
+
+function fromPairs<T>(values: [string, T][]): { [key: string]: T; } {
+  return values.reduce((acc, [key, value]) => Object.assign(acc, { [key]: value }), <{ [key: string]: T; }>{});
+}
+
+function uniqBy<T>(items: T[], iteratee: (item: T) => string): T[] {
+  const keys: { [key: string]: boolean; } = {};
+  return items.reduce((acc, item) => {
+    const key = iteratee(item);
+    if (key in keys) { return acc; }
+    keys[key] = true;
+    acc.push(item);
+    return acc;
+  }, <T[]>[]);
+}
+
+function mixin<DEST, SRC>(dest: DEST, src: SRC): DEST & SRC {
+  for (let prop in src) {
+    if (Object.hasOwnProperty.call(src, prop)) {
+      (<any>dest)[prop] = src[prop];
+    }
+  }
+  return <any>dest;
+}
+
+function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
+  return <T[]>array.filter(Boolean);
+}
+
+export = MonacoEditorWebpackPlugin;

+ 109 - 53
languages.js → src/languages.ts

@@ -1,37 +1,48 @@
-module.exports = {
-  apex: {
+import { IFeatureDefinition } from "./types";
+
+const languagesArr: IFeatureDefinition[] = [
+  {
+    label: 'apex',
     entry: 'vs/basic-languages/apex/apex.contribution',
     worker: undefined,
   },
-  azcli: {
+  {
+    label: 'azcli',
     entry: 'vs/basic-languages/azcli/azcli.contribution',
     worker: undefined,
   },
-  bat: {
+  {
+    label: 'bat',
     entry: 'vs/basic-languages/bat/bat.contribution',
     worker: undefined,
   },
-  clojure: {
+  {
+    label: 'clojure',
     entry: 'vs/basic-languages/clojure/clojure.contribution',
     worker: undefined,
   },
-  coffee: {
+  {
+    label: 'coffee',
     entry: 'vs/basic-languages/coffee/coffee.contribution',
     worker: undefined,
   },
-  cpp: {
+  {
+    label: 'cpp',
     entry: 'vs/basic-languages/cpp/cpp.contribution',
     worker: undefined,
   },
-  csharp: {
+  {
+    label: 'csharp',
     entry: 'vs/basic-languages/csharp/csharp.contribution',
     worker: undefined,
   },
-  csp: {
+  {
+    label: 'csp',
     entry: 'vs/basic-languages/csp/csp.contribution',
     worker: undefined,
   },
-  css: {
+  {
+    label: 'css',
     entry: [
       'vs/basic-languages/css/css.contribution',
       'vs/language/css/monaco.contribution',
@@ -42,27 +53,33 @@ module.exports = {
       fallback: 'vs/language/css/cssWorker',
     },
   },
-  dockerfile: {
+  {
+    label: 'dockerfile',
     entry: 'vs/basic-languages/dockerfile/dockerfile.contribution',
     worker: undefined,
   },
-  fsharp: {
+  {
+    label: 'fsharp',
     entry: 'vs/basic-languages/fsharp/fsharp.contribution',
     worker: undefined,
   },
-  go: {
+  {
+    label: 'go',
     entry: 'vs/basic-languages/go/go.contribution',
     worker: undefined,
   },
-  graphql: {
+  {
+    label: 'graphql',
     entry: 'vs/basic-languages/graphql/graphql.contribution',
     worker: undefined,
   },
-  handlebars: {
+  {
+    label: 'handlebars',
     entry: 'vs/basic-languages/handlebars/handlebars.contribution',
     worker: undefined,
   },
-  html: {
+  {
+    label: 'html',
     entry: [
       'vs/basic-languages/html/html.contribution',
       'vs/language/html/monaco.contribution',
@@ -73,19 +90,23 @@ module.exports = {
       fallback: 'vs/language/html/htmlWorker',
     },
   },
-  ini: {
+  {
+    label: 'ini',
     entry: 'vs/basic-languages/ini/ini.contribution',
     worker: undefined,
   },
-  java: {
+  {
+    label: 'java',
     entry: 'vs/basic-languages/java/java.contribution',
     worker: undefined,
   },
-  javascript: {
+  {
+    label: 'javascript',
     entry: 'vs/basic-languages/javascript/javascript.contribution',
     worker: undefined,
   },
-  json: {
+  {
+    label: 'json',
     entry: 'vs/language/json/monaco.contribution',
     worker: {
       id: 'vs/language/json/jsonWorker',
@@ -93,119 +114,148 @@ module.exports = {
       fallback: 'vs/language/json/jsonWorker',
     },
   },
-  less: {
+  {
+    label: 'less',
     entry: 'vs/basic-languages/less/less.contribution',
     worker: undefined,
   },
-  lua: {
+  {
+    label: 'lua',
     entry: 'vs/basic-languages/lua/lua.contribution',
     worker: undefined,
   },
-  markdown: {
+  {
+    label: 'markdown',
     entry: 'vs/basic-languages/markdown/markdown.contribution',
     worker: undefined,
   },
-  msdax: {
+  {
+    label: 'msdax',
     entry: 'vs/basic-languages/msdax/msdax.contribution',
     worker: undefined,
   },
-  mysql: {
+  {
+    label: 'mysql',
     entry: 'vs/basic-languages/mysql/mysql.contribution',
     worker: undefined,
   },
-  objective: {
+  {
+    label: 'objective',
     entry: 'vs/basic-languages/objective-c/objective-c.contribution',
     worker: undefined,
   },
-  perl: {
+  {
+    label: 'perl',
     entry: 'vs/basic-languages/perl/perl.contribution',
     worker: undefined,
   },
-  pgsql: {
+  {
+    label: 'pgsql',
     entry: 'vs/basic-languages/pgsql/pgsql.contribution',
     worker: undefined,
   },
-  php: {
+  {
+    label: 'php',
     entry: 'vs/basic-languages/php/php.contribution',
     worker: undefined,
   },
-  postiats: {
+  {
+    label: 'postiats',
     entry: 'vs/basic-languages/postiats/postiats.contribution',
     worker: undefined,
   },
-  powerquery: {
+  {
+    label: 'powerquery',
     entry: 'vs/basic-languages/powerquery/powerquery.contribution',
     worker: undefined,
   },
-  powershell: {
+  {
+    label: 'powershell',
     entry: 'vs/basic-languages/powershell/powershell.contribution',
     worker: undefined,
   },
-  pug: {
+  {
+    label: 'pug',
     entry: 'vs/basic-languages/pug/pug.contribution',
     worker: undefined,
   },
-  python: {
+  {
+    label: 'python',
     entry: 'vs/basic-languages/python/python.contribution',
     worker: undefined,
   },
-  r: {
+  {
+    label: 'r',
     entry: 'vs/basic-languages/r/r.contribution',
     worker: undefined,
   },
-  razor: {
+  {
+    label: 'razor',
     entry: 'vs/basic-languages/razor/razor.contribution',
     worker: undefined,
   },
-  redis: {
+  {
+    label: 'redis',
     entry: 'vs/basic-languages/redis/redis.contribution',
     worker: undefined,
   },
-  redshift: {
+  {
+    label: 'redshift',
     entry: 'vs/basic-languages/redshift/redshift.contribution',
     worker: undefined,
   },
-  ruby: {
+  {
+    label: 'ruby',
     entry: 'vs/basic-languages/ruby/ruby.contribution',
     worker: undefined,
   },
-  rust: {
+  {
+    label: 'rust',
     entry: 'vs/basic-languages/rust/rust.contribution',
     worker: undefined,
   },
-  sb: {
+  {
+    label: 'sb',
     entry: 'vs/basic-languages/sb/sb.contribution',
     worker: undefined,
   },
-  scheme: {
+  {
+    label: 'scheme',
     entry: 'vs/basic-languages/scheme/scheme.contribution',
     worker: undefined,
   },
-  scss: {
+  {
+    label: 'scss',
     entry: 'vs/basic-languages/scss/scss.contribution',
     worker: undefined,
   },
-  shell: {
+  {
+    label: 'shell',
     entry: 'vs/basic-languages/shell/shell.contribution',
     worker: undefined,
   },
-  solidity: {
+  {
+    label: 'solidity',
     entry: 'vs/basic-languages/solidity/solidity.contribution',
     worker: undefined,
   },
-  sql: {
+  {
+    label: 'sql',
     entry: 'vs/basic-languages/sql/sql.contribution',
     worker: undefined,
   },
-  st: {
+  {
+    label: 'st',
     entry: 'vs/basic-languages/st/st.contribution',
     worker: undefined,
   },
-  swift: {
+  {
+    label: 'swift',
     entry: 'vs/basic-languages/swift/swift.contribution',
     worker: undefined,
   },
-  typescript: {
+  {
+    label: 'typescript',
     entry: [
       'vs/basic-languages/typescript/typescript.contribution',
       'vs/language/typescript/monaco.contribution',
@@ -216,16 +266,22 @@ module.exports = {
       fallback: 'vs/language/typescript/tsWorker',
     },
   },
-  vb: {
+  {
+    label: 'vb',
     entry: 'vs/basic-languages/vb/vb.contribution',
     worker: undefined,
   },
-  xml: {
+  {
+    label: 'xml',
     entry: 'vs/basic-languages/xml/xml.contribution',
     worker: undefined,
   },
-  yaml: {
+  {
+    label: 'yaml',
     entry: 'vs/basic-languages/yaml/yaml.contribution',
     worker: undefined,
   },
-};
+];
+
+export const languagesById: { [language: string]: IFeatureDefinition; } = {};
+languagesArr.forEach(language => languagesById[language.label] = language);

+ 3 - 3
loaders/include.js → src/loaders/include.ts

@@ -1,6 +1,6 @@
 const loaderUtils = require('loader-utils');
 
-module.exports.pitch = function pitch(remainingRequest) {
+export function pitch(this: any, remainingRequest: any) {
   const { globals = undefined, pre = [], post = [] } = loaderUtils.getOptions(this) || {};
 
   // HACK: NamedModulesPlugin overwrites existing modules when requesting the same module via
@@ -15,8 +15,8 @@ module.exports.pitch = function pitch(remainingRequest) {
       ? Object.keys(globals).map((key) => `self[${JSON.stringify(key)}] = ${globals[key]};`)
       : []
     ),
-    ...pre.map((include) => `require(${loaderUtils.stringifyRequest(this, include)});`),
+    ...pre.map((include: any) => `require(${loaderUtils.stringifyRequest(this, include)});`),
     `module.exports = require(${loaderUtils.stringifyRequest(this, `!!${remainingRequest}`)});`,
-    ...post.map((include) => `require(${loaderUtils.stringifyRequest(this, include)});`),
+    ...post.map((include: any) => `require(${loaderUtils.stringifyRequest(this, include)});`),
   ].join('\n');
 };

+ 18 - 14
plugins/AddWorkerEntryPointPlugin.js → src/plugins/AddWorkerEntryPointPlugin.ts

@@ -1,10 +1,19 @@
+import * as webpack from 'webpack';
 const webpackVersion = require('webpack/package.json').version;
 const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
 const LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin');
 const WebWorkerTemplatePlugin = require('webpack/lib/webworker/WebWorkerTemplatePlugin');
 
-function getCompilerHook(compiler, {id, entry, filename, chunkFilename, plugins}) {
-  return function(compilation, callback) {
+export interface IAddWorkerEntryPointPluginOptions {
+  id: string;
+  entry: string;
+  filename: string;
+  chunkFilename?: string;
+  plugins: webpack.Plugin[];
+}
+
+function getCompilerHook(compiler: webpack.Compiler, { id, entry, filename, chunkFilename, plugins }: IAddWorkerEntryPointPluginOptions) {
+  return function (compilation: webpack.compilation.Compilation, callback: Function) {
     const outputOptions = {
       filename,
       chunkFilename,
@@ -12,7 +21,7 @@ function getCompilerHook(compiler, {id, entry, filename, chunkFilename, plugins}
       // HACK: globalObject is necessary to fix https://github.com/webpack/webpack/issues/6642
       globalObject: 'this',
     };
-    const childCompiler = compilation.createChildCompiler(id, outputOptions, [
+    const childCompiler = (<any>compilation).createChildCompiler(id, outputOptions, [
       new WebWorkerTemplatePlugin(),
       new LoaderTargetPlugin('webworker'),
     ]);
@@ -23,18 +32,15 @@ function getCompilerHook(compiler, {id, entry, filename, chunkFilename, plugins}
   }
 }
 
-class AddWorkerEntryPointPlugin {
-  constructor({
-    id,
-    entry,
-    filename,
-    chunkFilename = undefined,
-    plugins = undefined,
-  }) {
+export class AddWorkerEntryPointPlugin implements webpack.Plugin {
+
+  private readonly options: IAddWorkerEntryPointPluginOptions;
+
+  constructor({ id, entry, filename, chunkFilename = undefined, plugins }: IAddWorkerEntryPointPluginOptions) {
     this.options = { id, entry, filename, chunkFilename, plugins };
   }
 
-  apply(compiler) {
+  apply(compiler: webpack.Compiler) {
     const compilerHook = getCompilerHook(compiler, this.options);
     if (webpackVersion < '4') {
       compiler.plugin('make', compilerHook);
@@ -43,5 +49,3 @@ class AddWorkerEntryPointPlugin {
     }
   }
 }
-
-module.exports = AddWorkerEntryPointPlugin;

+ 12 - 0
src/types.ts

@@ -0,0 +1,12 @@
+
+export interface IWorkerDefinition {
+  id: string;
+  entry: string;
+  fallback: string | undefined;
+}
+
+export interface IFeatureDefinition {
+  label: string;
+  entry: string | string[] | undefined;
+  worker?: IWorkerDefinition;
+}

+ 1 - 1
test/webpack.config.js

@@ -1,4 +1,4 @@
-const MonacoWebpackPlugin = require('../index.js');
+const MonacoWebpackPlugin = require('../out/index.js');
 const path = require('path');
 
 module.exports = {

+ 15 - 0
tsconfig.json

@@ -0,0 +1,15 @@
+{
+    "compilerOptions": {
+        "module": "commonjs",
+        "outDir": "out",
+        "target": "es6",
+        "declaration": true,
+        "strict": true
+    },
+    "include": [
+        "src"
+    ],
+    "exclude": [
+        "node_modules"
+    ]
+}

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels