diff --git a/packages/lwc-compiler/.npmignore b/packages/lwc-compiler/.npmignore
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/package.json b/packages/lwc-compiler/package.json
old mode 100755
new mode 100644
index d4afe286c4..ca016952ab
--- a/packages/lwc-compiler/package.json
+++ b/packages/lwc-compiler/package.json
@@ -3,21 +3,19 @@
"version": "0.20.0",
"description": "LWC compiler",
"main": "dist/commonjs/index.js",
- "typings": "dist/types/index.d.ts",
"author": "",
"license": "ISC",
"scripts": {
"clean": "rm -rf dist",
- "build": "yarn compile && yarn update:version",
- "compile": "echo 'Building compiler...' && DIR=`pwd` && cd ../../ && tsc -p $DIR/tsconfig.json",
- "update:version": "node ./scripts/update-compiler-version.js",
+ "build": "echo 'Building compiler...' && DIR=`pwd` && cd ../../ && tsc -p $DIR/tsconfig.json",
+ "build:all": "",
+ "build:umd": "webpack --progress",
"test": "DIR=`pwd` && cd ../../ && jest $DIR"
},
"dependencies": {
"@babel/core": "7.0.0-beta.40",
"@babel/plugin-proposal-class-properties": "7.0.0-beta.40",
"@babel/plugin-proposal-object-rest-spread": "7.0.0-beta.40",
- "@types/chokidar": "^1.7.5",
"babel-plugin-transform-lwc-class": "0.20.0",
"babel-preset-compat": "0.17.40",
"babel-preset-minify": "0.4.0-alpha.caaefb4c",
@@ -27,12 +25,10 @@
"postcss": "~6.0.19",
"postcss-plugin-lwc": "0.20.0",
"postcss-selector-parser": "^3.1.1",
- "rollup": "~0.56.5",
+ "rollup": "~0.56.2",
"rollup-plugin-replace": "^2.0.0"
},
"devDependencies": {
- "@types/babel-core": "^6.25.3",
- "magic-string": "^0.22.4",
"string-replace-webpack-plugin": "0.1.3",
"webpack": "^3.11.0"
}
diff --git a/packages/lwc-compiler/scripts/update-compiler-version.js b/packages/lwc-compiler/scripts/update-compiler-version.js
deleted file mode 100644
index a61306bfc0..0000000000
--- a/packages/lwc-compiler/scripts/update-compiler-version.js
+++ /dev/null
@@ -1,34 +0,0 @@
-const path = require("path");
-const replace = require("rollup-plugin-replace");
-const { rollup } = require("rollup");
-const { version } = require("../package.json");
-
-async function updateVersion(version) {
- const sourcePath = path.resolve("dist/commonjs/index.js");
-
- const result = await rollup({
- input: sourcePath,
- plugins: [
- replace({
- __VERSION__: version
- })
- ]
- });
-
- await result.write({
- file: sourcePath,
- format: "cjs",
- sourcemap: false, // keep typescript generated map to stay consistent with the rest of the files.
- });
-
- console.log("Compiler version: ", version);
-}
-
-if (!version || typeof version !== "string") {
- throw new Error(
- "Failed to update compiler version. Expected version value as a string, received: " +
- version
- );
-}
-
-updateVersion(version);
diff --git a/packages/lwc-compiler/src/__tests__/fixtures.spec.js b/packages/lwc-compiler/src/__tests__/fixtures.spec.js
new file mode 100644
index 0000000000..e907be2ac0
--- /dev/null
+++ b/packages/lwc-compiler/src/__tests__/fixtures.spec.js
@@ -0,0 +1,440 @@
+/* eslint-env node, jest */
+
+const { compile } = require('../index');
+const { fixturePath, readFixture, pretify } = require('./utils');
+
+describe('validate options', () => {
+ it('should validate entry type', () => {
+ expect(() => compile()).toThrow(/Expected a string for entry/);
+ });
+
+ it('should validate mode', () => {
+ expect(() =>
+ compile('/x/foo/foo.js', {
+ mode: 'foo',
+ }),
+ ).toThrow(
+ /Expected a mode in dev, prod, compat, prod_compat, all. Received instead foo/,
+ );
+ });
+
+ it('should validate sources option format', () => {
+ expect(() =>
+ compile('/x/foo/foo.js', {
+ sources: {
+ '/x/foo/foo.js': true,
+ },
+ }),
+ ).toThrow(
+ /in-memory module resolution expects values to be string. Received true for key \/x\/foo\/foo.js/,
+ );
+ });
+});
+
+describe('stylesheet', () => {
+ it('should import the associated stylesheet by default', async () => {
+ const { code } = await compile(
+ fixturePath('namespaced_folder/styled/styled.js'),
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-styled.js')),
+ );
+ });
+
+ it('should import compress css in prod mode', async () => {
+ const { code } = await compile(
+ fixturePath('namespaced_folder/styled/styled.js'),
+ {
+ mode: 'prod'
+ }
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-styled-prod.js')),
+ );
+ });
+});
+
+describe('component name and namespace override', () => {
+ it('should be able to override module name', async () => {
+ const { code } = await compile('/x/foo/foo.js', {
+ componentName: 'bar',
+ format: 'amd',
+ mode: 'prod',
+ sources: {
+ '/x/foo/foo.js': `console.log('foo')`,
+ },
+ });
+
+ expect(pretify(code)).toBe(
+ pretify(`define("x-bar",function(){console.log("foo")});`),
+ );
+ });
+
+ it('should be able to override module namespace', async () => {
+ const { code } = await compile('/x/foo/foo.js', {
+ componentNamespace: 'bar',
+ format: 'amd',
+ mode: 'prod',
+ sources: {
+ '/x/foo/foo.js': `console.log('foo')`,
+ },
+ });
+
+ expect(pretify(code)).toBe(
+ pretify(`define("bar-foo",function(){console.log("foo")});`),
+ );
+ });
+});
+
+describe('compile from file system', () => {
+ it('compiles module with no option and default namespace', async () => {
+ const { code, metadata } = await compile(
+ fixturePath('namespaced_folder/default/default.js'),
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(
+ readFixture(
+ 'expected-compile-with-no-options-and-default-namespace.js',
+ ),
+ ),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [],
+ references: [
+ {name: 'engine', type: 'module' }
+ ]
+ });
+ });
+
+ it('compiles with namespace mapping', async () => {
+ const { code, metadata } = await compile(
+ fixturePath('namespaced_folder/ns1/cmp1/cmp1.js'),
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-mapping-namespace-from-path.js')),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [],
+ references: [
+ { name: 'engine', type: 'module' }
+ ]
+ });
+ });
+});
+
+describe('compile from in-memory', () => {
+ it('compiles to ESModule by deafult', async () => {
+ const { code, metadata } = await compile('/x/foo/foo.js', {
+ mapNamespaceFromPath: true,
+ sources: {
+ '/x/foo/foo.js': readFixture(
+ 'class_and_template/class_and_template.js',
+ ),
+ '/x/foo/foo.html': readFixture(
+ 'class_and_template/class_and_template.html',
+ ),
+ },
+ });
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-sources-namespaced.js')),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [],
+ references: [
+ { name: 'engine', type: 'module' }
+ ]
+ });
+ });
+
+ it('respects the output format', async () => {
+ const { code, metadata } = await compile('/x/foo/foo.js', {
+ format: 'amd',
+ mapNamespaceFromPath: true,
+ sources: {
+ '/x/foo/foo.js': readFixture(
+ 'class_and_template/class_and_template.js',
+ ),
+ '/x/foo/foo.html': readFixture(
+ 'class_and_template/class_and_template.html',
+ ),
+ },
+ });
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-sources-namespaced-format.js')),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [],
+ references: [
+ { name: 'engine', type: 'module' }
+ ]
+ });
+ });
+
+ it('respects the output format', async () => {
+ const {
+ code,
+ metadata,
+ } = await compile('myns/relative_import/relative_import.js', {
+ format: 'amd',
+ mapNamespaceFromPath: true,
+ sources: {
+ 'myns/relative_import/relative_import.html': readFixture(
+ 'relative_import/relative_import.html',
+ ),
+ 'myns/relative_import/relative_import.js': readFixture(
+ 'relative_import/relative_import.js',
+ ),
+ 'myns/relative_import/relative.js': readFixture(
+ 'relative_import/relative.js',
+ ),
+ 'myns/relative_import/other/relative2.js': readFixture(
+ 'relative_import/other/relative2.js',
+ ),
+ 'myns/relative_import/other/relative3.js': readFixture(
+ 'relative_import/other/relative3.js',
+ ),
+ },
+ });
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-relative-import.js')),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [],
+ references: [
+ { name: 'engine', type: 'module' }
+ ]
+ });
+ });
+});
+
+describe('mode generation', () => {
+ it('handles prod mode', async () => {
+ const { code, metadata } = await compile(
+ fixturePath('class_and_template/class_and_template.js'),
+ {
+ format: 'amd',
+ mode: 'prod',
+ },
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-prod-mode.js')),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [],
+ references: [
+ { name: 'engine', type: 'module' }
+ ]
+ });
+ });
+
+ it('handles compat mode', async () => {
+ const { code, metadata } = await compile(
+ fixturePath('class_and_template/class_and_template.js'),
+ {
+ format: 'amd',
+ mode: 'compat',
+ },
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-compat-mode.js')),
+ );
+
+ expect(metadata).toMatchObject({
+ decorators: [],
+ references: [
+ { name: 'engine', type: 'module' }
+ ]
+ });
+ });
+
+ it('handles prod-compat mode', async () => {
+ const { code, metadata } = await compile(
+ fixturePath('class_and_template/class_and_template.js'),
+ {
+ format: 'amd',
+ mode: 'prod_compat',
+ },
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-prod_compat-mode.js')),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [],
+ references: [
+ { name: 'engine', type: 'module' }
+ ]
+ });
+ });
+
+ it('handles all modes', async () => {
+ const res = await compile(
+ fixturePath('class_and_template/class_and_template.js'),
+ {
+ format: 'amd',
+ mode: 'all',
+ },
+ );
+
+ expect(Object.keys(res)).toEqual([
+ 'dev',
+ 'prod',
+ 'compat',
+ 'prod_compat',
+ ]);
+
+ for (let mode of Object.keys(res)) {
+ const { code, metadata } = res[mode];
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture(`expected-${mode}-mode.js`)),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [],
+ references: [
+ { name: 'engine', type: 'module' }
+ ]
+ });
+ }
+ });
+});
+
+describe('node env', function () {
+ it('does not remove production code when no NODE_ENV option is specified', async () => {
+ const previous = process.env.NODE_ENV;
+ process.env.NODE_ENV = undefined;
+ const { code, metadata } = await compile(
+ fixturePath('node_env/node_env.js'),
+ {
+ mode: 'dev',
+ },
+ );
+ process.env.NODE_ENV = previous;
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-node-env-dev.js')),
+ );
+ });
+
+ it('does removes production code when process.env.NODE_ENV is production', async () => {
+ const previous = process.env.NODE_ENV;
+ process.env.NODE_ENV = 'production';
+ const { code, metadata } = await compile(
+ fixturePath('node_env/node_env.js'),
+ {
+ mode: 'dev',
+ },
+ );
+ process.env.NODE_ENV = previous;
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-node-env-prod.js')),
+ );
+ });
+
+ it('removes production code when NODE_ENV option is production', async () => {
+ const { code, metadata } = await compile(
+ fixturePath('node_env/node_env.js'),
+ {
+ mode: 'dev',
+ env: {
+ NODE_ENV: 'production',
+ }
+ },
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-node-env-prod.js')),
+ );
+ });
+
+ it('does not remove production code when in NODE_ENV option is development', async () => {
+ const { code, metadata } = await compile(
+ fixturePath('node_env/node_env.js'),
+ {
+ mode: 'dev',
+ env: {
+ NODE_ENV: 'development',
+ }
+ },
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-node-env-dev.js')),
+ );
+ });
+});
+
+describe('metadata output', () => {
+ it('decorators and references', async () => {
+ const { code, metadata } = await compile('/x/foo/foo.js', {
+ mapNamespaceFromPath: true,
+ sources: {
+ '/x/foo/foo.js': readFixture(
+ 'metadata/metadata.js',
+ ),
+ '/x/foo/foo.html': readFixture(
+ 'metadata/metadata.html',
+ ),
+ },
+ });
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-sources-metadata.js')),
+ );
+
+ expect(metadata).toEqual({
+ decorators: [
+ {
+ type: 'api',
+ targets: [
+ { type: 'property', name: 'publicProp' },
+ { type: 'method', name: 'publicMethod' }
+ ]
+ },
+ {
+ type: 'wire',
+ targets: [
+ {
+ type: 'property',
+ adapter: { name: 'getTodo', reference: 'todo' },
+ name: 'wiredProp',
+ params: {},
+ static: {}
+ },
+ {
+ type: 'method',
+ adapter: { name: 'getHello', reference: '@schema/foo.bar' },
+ name: 'wiredMethod',
+ params: { name: 'publicProp' },
+ static: { 'fields': ['one', 'two'] }
+ }
+ ]
+ }
+ ],
+ references: [
+ { name: 'x-bar', type: 'component' },
+ { name: 'engine', type: 'module' },
+ { name: 'todo', type: 'module' },
+ { name: '@schema/foo.bar', type: 'module' }
+ ]
+ });
+ });
+});
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/class_and_template/class_and_template.html b/packages/lwc-compiler/src/__tests__/fixtures/class_and_template/class_and_template.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/class_and_template/class_and_template.js b/packages/lwc-compiler/src/__tests__/fixtures/class_and_template/class_and_template.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-all-modes.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-all-modes.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-babel-compat.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-babel-compat.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-babel.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-babel.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-compat-mode.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-compat-mode.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-compile-individual-resources.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-compile-individual-resources.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-compile-with-no-options-and-default-namespace.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-compile-with-no-options-and-default-namespace.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-dev-mode.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-dev-mode.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-external-dependency.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-external-dependency.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-mapping-namespace-from-path.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-mapping-namespace-from-path.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-node-env-dev.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-node-env-dev.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-node-env-prod.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-node-env-prod.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-prod-mode.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-prod-mode.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-prod_compat-mode.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-prod_compat-mode.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-relative-import.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-relative-import.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-sources-metadata.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-sources-metadata.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-sources-namespaced-format.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-sources-namespaced-format.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-sources-namespaced.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-sources-namespaced.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-styled-prod.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-styled-prod.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/expected-styled.js b/packages/lwc-compiler/src/__tests__/fixtures/expected-styled.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/flat_structure/app.js b/packages/lwc-compiler/src/__tests__/fixtures/flat_structure/app.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/flat_structure/simpleClass1.html b/packages/lwc-compiler/src/__tests__/fixtures/flat_structure/simpleClass1.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/flat_structure/simpleClass1.js b/packages/lwc-compiler/src/__tests__/fixtures/flat_structure/simpleClass1.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/metadata/metadata.html b/packages/lwc-compiler/src/__tests__/fixtures/metadata/metadata.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/metadata/metadata.js b/packages/lwc-compiler/src/__tests__/fixtures/metadata/metadata.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/babel/babel.js b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/babel/babel.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/custom/foo-bar.html b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/custom/foo-bar.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/custom/foo-bar.js b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/custom/foo-bar.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/default/default.html b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/default/default.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/default/default.js b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/default/default.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/ns1/cmp1/cmp1.html b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/ns1/cmp1/cmp1.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/ns1/cmp1/cmp1.js b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/ns1/cmp1/cmp1.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/ns2/components/cmp1/cmp1.html b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/ns2/components/cmp1/cmp1.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/ns2/components/cmp1/cmp1.js b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/ns2/components/cmp1/cmp1.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/styled/styled.css b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/styled/styled.css
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/styled/styled.html b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/styled/styled.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/styled/styled.js b/packages/lwc-compiler/src/__tests__/fixtures/namespaced_folder/styled/styled.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/node_env/node_env.html b/packages/lwc-compiler/src/__tests__/fixtures/node_env/node_env.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/node_env/node_env.js b/packages/lwc-compiler/src/__tests__/fixtures/node_env/node_env.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/relative_import/other/relative2.js b/packages/lwc-compiler/src/__tests__/fixtures/relative_import/other/relative2.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/relative_import/other/relative3.js b/packages/lwc-compiler/src/__tests__/fixtures/relative_import/other/relative3.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/relative_import/relative.js b/packages/lwc-compiler/src/__tests__/fixtures/relative_import/relative.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/relative_import/relative_import.html b/packages/lwc-compiler/src/__tests__/fixtures/relative_import/relative_import.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/relative_import/relative_import.js b/packages/lwc-compiler/src/__tests__/fixtures/relative_import/relative_import.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/fixtures/template/template.html b/packages/lwc-compiler/src/__tests__/fixtures/template/template.html
old mode 100755
new mode 100644
diff --git a/packages/lwc-compiler/src/__tests__/index.spec.js b/packages/lwc-compiler/src/__tests__/index.spec.js
new file mode 100644
index 0000000000..deb2ad776c
--- /dev/null
+++ b/packages/lwc-compiler/src/__tests__/index.spec.js
@@ -0,0 +1,194 @@
+/* eslint-env node, jest */
+
+const { compile, transform } = require('../index');
+const { pretify } = require('./utils');
+
+const VALID_TEST_JS = `
+import label from '@label/mylabel';
+function isTrue() {
+ return label;
+}
+isTrue();
+`.trim();
+
+describe('compile', () => {
+ it('should validate entry type', () => {
+ expect(() => compile()).toThrow(/Expected a string for entry/);
+ });
+
+ it('should validate mode', () => {
+ expect(() =>
+ compile('/x/foo/foo.js', {
+ mode: 'foo',
+ }),
+ ).toThrow(
+ /Expected a mode in dev, prod, compat, prod_compat, all. Received instead foo/,
+ );
+ });
+
+ it('should validate sources option format', () => {
+ expect(() =>
+ compile('/x/foo/foo.js', {
+ sources: {
+ '/x/foo/foo.js': true,
+ },
+ }),
+ ).toThrow(
+ /in-memory module resolution expects values to be string. Received true for key \/x\/foo\/foo.js/,
+ );
+ });
+ // TODO: uncomment once compile output format changes
+ // it.only('should return status, diagnostics, references, and bundles', () => {
+ // const config = {
+ // sources: {
+ // '/x/foo/foo.js': VALID_TEST_JS,
+ // },
+ // entry: '/x/foo/foo.js',
+ // moduleName: 'foo',
+ // moduleNamespace: 'x',
+ // format: 'whoknows',
+ // };
+ // const { status, diagnostics, references, bundles } = compile();
+ // expect(status).toBe('ok');
+ // expect(diagnostics.length).toBe(0);
+ // expect(references.length > 0).toBe(true);
+ // expect(bundles.length).toBe(1);
+ // });
+});
+
+describe('transform', () => {
+ it('should validate presence of src', () => {
+ expect(() => transform()).toThrow(
+ /Expect a string for source. Received undefined/,
+ );
+ });
+
+ it('should validate presence of id', () => {
+ expect(() => transform(`console.log('Hello')`)).toThrow(
+ /Expect a string for id. Received undefined/,
+ );
+ });
+
+ it('should apply transformation for javascript file', async () => {
+ const actual = `
+ import { Element } from 'engine';
+ export default class Foo extends Element {}
+ `;
+
+ const expected = `
+ import _tmpl from "./foo.html";
+ import { Element } from 'engine';
+ export default class Foo extends Element {
+ render() {
+ return _tmpl;
+ }
+ }
+ Foo.style = _tmpl.style;
+ `;
+
+ const { code } = await transform(actual, 'foo.js', {
+ moduleNamespace: 'x',
+ moduleName: 'foo',
+ });
+
+ expect(pretify(code)).toBe(pretify(expected));
+ });
+
+ it('should apply transformation for template file', async () => {
+ const actual = `
+
+ Hello
+
+ `;
+
+ const expected = `
+ import style from './foo.css'
+
+ export default function tmpl($api, $cmp, $slotset, $ctx) {
+ const {
+ t: api_text,
+ h: api_element
+ } = $api;
+
+ return [api_element("div", {
+ key: 1
+ }, [api_text("Hello")])];
+ }
+
+ if (style) {
+ const tagName = 'x-foo';
+ const token = 'x-foo_foo';
+ tmpl.token = token;
+ tmpl.style = style(tagName, token);
+ }
+ `;
+
+ const { code } = await transform(actual, 'foo.html', {
+ moduleNamespace: 'x',
+ moduleName: 'foo',
+ });
+
+ expect(pretify(code)).toBe(pretify(expected));
+ });
+
+ it('should apply transformation for stylesheet file', async () => {
+ const actual = `
+ div {
+ background-color: red;
+ }
+ `;
+
+ const expected = `
+ function style(tagName, token) {
+ return \`
+ div[\${token}] {
+ background-color: red;
+ }
+ \`;
+ }
+ export default style;
+ `;
+
+ const { code } = await transform(actual, 'foo.css', {
+ moduleNamespace: 'x',
+ moduleName: 'foo',
+ });
+
+ expect(pretify(code)).toBe(pretify(expected));
+ });
+
+ it('javascript metadata', async () => {
+ const content = `
+ import { Element, api } from 'engine';
+ /** Foo doc */
+ export default class Foo extends Element {
+ _privateTodo;
+ @api get todo () {
+ return this._privateTodo;
+ }
+ @api set todo (val) {
+ return this._privateTodo = val;
+ }
+ @api
+ index;
+ }
+ `;
+
+ const result = await transform(content, 'foo.js', {
+ moduleNamespace: 'x',
+ moduleName: 'foo',
+ });
+ const metadata = result.metadata;
+ expect(metadata.decorators).toEqual([
+ {
+ type: 'api',
+ targets: [
+ { type: 'property', name: 'todo' },
+ { type: 'property', name: 'index' }
+ ]
+ }
+ ]);
+ expect(metadata.doc).toBe('Foo doc');
+ expect(metadata.declarationLoc).toEqual({ start: { line: 4, column: 12 }, end: { line: 14, column: 13 } });
+ });
+});
diff --git a/packages/lwc-compiler/src/__tests__/index.spec.ts b/packages/lwc-compiler/src/__tests__/index.spec.ts
deleted file mode 100755
index f09502b8b4..0000000000
--- a/packages/lwc-compiler/src/__tests__/index.spec.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { compile, transform, version } from "../index";
-
-const COMPILER_CONFIG = {
- name: "foo",
- namespace: "x",
- files: { "foo.js": "debugger" },
- outputConfig: {
- env: { NODE_ENV: "development" },
- minify: false,
- compat: false
- }
-};
-
-describe("test index entry points", () => {
- test("able to invoke compiler", async () => {
- const { result, success } = await compile(COMPILER_CONFIG);
- expect(success).toBe(true);
- expect(result).toBeDefined();
- });
-
- test("able to invoke transformer", async () => {
- // transform should normalize options and append outputConfig
- const config = {
- name: "foo",
- namespace: "x",
- files: { "foo.js": "debugger" },
- };
- const { code } = await transform("debugger", "file.js", config);
- expect(code).toBe("debugger;");
- });
-
- test("able to retrieve version", () => {
- expect(version).toBeDefined();
- });
-});
diff --git a/packages/lwc-compiler/src/__tests__/regression.spec.js b/packages/lwc-compiler/src/__tests__/regression.spec.js
new file mode 100644
index 0000000000..66ded3481f
--- /dev/null
+++ b/packages/lwc-compiler/src/__tests__/regression.spec.js
@@ -0,0 +1,46 @@
+const { compile } = require('../index');
+const { fixturePath, readFixture, pretify } = require('./utils');
+
+describe('resgression test', () => {
+ it('#743 - Object rest spread throwing', async () => {
+ const actual = `const base = { foo: true }; const res = { ...base, bar: false };`;
+ const expected = `const base = {
+ foo: true
+};
+const res = Object.assign({}, base, {
+ bar: false
+});`;
+
+ const { code } = await compile('/x/foo/foo.js', {
+ sources: {
+ '/x/foo/foo.js': actual,
+ },
+ });
+
+ expect(pretify(code)).toBe(pretify(expected));
+ });
+});
+
+describe('smoke test for babel transform', () => {
+ it('should transpile none stage-4 syntax features in none-compat', async () => {
+ const { code } = await compile(
+ fixturePath('namespaced_folder/babel/babel.js'),
+ {
+ mode: 'dev'
+ }
+ );
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-babel.js')),
+ );
+ });
+
+ it('should transpile back to es5 in compat mode', async () => {
+ const { code } = await compile(
+ fixturePath('namespaced_folder/babel/babel.js'), { mode: 'compat' }
+ );
+
+ expect(pretify(code)).toBe(
+ pretify(readFixture('expected-babel-compat.js')),
+ );
+ });
+});
diff --git a/packages/lwc-compiler/src/__tests__/regression.spec.ts b/packages/lwc-compiler/src/__tests__/regression.spec.ts
deleted file mode 100755
index 4517ca3e82..0000000000
--- a/packages/lwc-compiler/src/__tests__/regression.spec.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { compile } from "../index";
-import { readFixture, pretify } from "./utils";
-
-describe("regression test", () => {
- it("#743 - Object rest spread throwing", async () => {
- const actual = `const base = { foo: true }; const res = { ...base, bar: false };`;
- const expected = `define('x-foo', function () {
- const base = {
- foo: true
- };
- const res = Object.assign({}, base, {
- bar: false
- });
- });`;
-
- const { result } = await compile({
- name: "foo",
- namespace: "x",
- files: {
- "foo.js": actual
- },
- });
- expect(pretify(result.code)).toBe(pretify(expected));
- });
-});
-
-describe("smoke test for babel transform", () => {
- it("should transpile none stage-4 syntax features in none-compat", async () => {
- const { result } = await compile({
- name: 'babel',
- namespace: 'x',
- files: {
- 'babel.js': readFixture("namespaced_folder/babel/babel.js")
- },
- outputConfig: { format: 'es' }
- }
- );
-
- expect(pretify(result.code)).toBe(pretify(readFixture("expected-babel.js")));
- });
-
- it("should transpile back to es5 in compat mode", async () => {
- const { result } = await compile({
- name: 'babel',
- namespace: 'x',
- files: {
- 'babel.js': readFixture("namespaced_folder/babel/babel.js")
- },
- outputConfig: {
- compat: true,
- format: 'es',
- }
- });
-
- expect(pretify(result.code)).toBe(
- pretify(readFixture("expected-babel-compat.js"))
- );
- });
-});
diff --git a/packages/lwc-compiler/src/__tests__/utils.ts b/packages/lwc-compiler/src/__tests__/utils.js
old mode 100755
new mode 100644
similarity index 58%
rename from packages/lwc-compiler/src/__tests__/utils.ts
rename to packages/lwc-compiler/src/__tests__/utils.js
index fb1160cc40..8b4d84b473
--- a/packages/lwc-compiler/src/__tests__/utils.ts
+++ b/packages/lwc-compiler/src/__tests__/utils.js
@@ -1,17 +1,19 @@
-import * as fs from 'fs';
-import * as path from 'path';
+/* eslint-env node */
+
+const fs = require('fs');
+const path = require('path');
const FIXTURE_DIR = path.join(__dirname, 'fixtures');
-export function fixturePath(location: string): string {
+function fixturePath(location) {
return path.join(FIXTURE_DIR, location);
}
-export function readFixture(location: string): string {
+function readFixture(location) {
return fs.readFileSync(fixturePath(location), 'utf-8');
}
-export function pretify(str: string): string {
+function pretify(str) {
return str.toString()
.replace(/^\s+|\s+$/, '')
.split('\n')
@@ -19,3 +21,9 @@ export function pretify(str: string): string {
.filter(line => line.length)
.join('\n');
}
+
+module.exports = {
+ fixturePath,
+ readFixture,
+ pretify
+};
diff --git a/packages/lwc-compiler/src/babel-plugins.ts b/packages/lwc-compiler/src/babel-plugins.js
old mode 100755
new mode 100644
similarity index 83%
rename from packages/lwc-compiler/src/babel-plugins.ts
rename to packages/lwc-compiler/src/babel-plugins.js
index bf81232103..4e355fbe76
--- a/packages/lwc-compiler/src/babel-plugins.ts
+++ b/packages/lwc-compiler/src/babel-plugins.js
@@ -33,11 +33,11 @@
* modules: false,
* };
*/
-import * as transformPublicFields from '@babel/plugin-proposal-class-properties';
-import * as transformObjectRestSpread from '@babel/plugin-proposal-object-rest-spread';
+
+import transformPublicFields from '@babel/plugin-proposal-class-properties';
+import transformObjectRestSpread from '@babel/plugin-proposal-object-rest-spread';
// Base babel configuration
-// TODO: Need to remove * on the parserOpts plugin - not advised by babel-core
export const BABEL_CONFIG_BASE = {
babelrc: false,
sourceMaps: true,
diff --git a/packages/lwc-compiler/src/bundle.js b/packages/lwc-compiler/src/bundle.js
new file mode 100644
index 0000000000..8189b6fb21
--- /dev/null
+++ b/packages/lwc-compiler/src/bundle.js
@@ -0,0 +1,72 @@
+import { rollup } from 'rollup';
+import * as rollupPluginReplace from 'rollup-plugin-replace';
+
+import { isCompat, isProd } from './modes';
+import rollupModuleResolver from './rollup-plugins/module-resolver';
+import rollupTransfrom from './rollup-plugins/transform';
+import rollupCompat from './rollup-plugins/compat';
+import rollupMinify from './rollup-plugins/minify';
+
+function rollupWarningOverride(warning) {
+ if (warning.code && warning.code === 'UNRESOLVED_IMPORT') {
+ return;
+ }
+
+ console.warn(warning.message);
+}
+
+function mergeMetadata(metadata) {
+ const dependencies = new Map((metadata.rollupDependencies || []).map(d => ([d, 'module'])));
+ const decorators = [];
+
+ for (let i in metadata) {
+ (metadata[i].templateDependencies || []).forEach(td => (dependencies.set(td, 'component')));
+ decorators.push(...(metadata[i].decorators || []));
+ }
+
+ return {
+ decorators,
+ references: Array.from(dependencies).map(d => ({name: d[0], type: d[1]}))
+ };
+}
+
+
+export default function bundle(entry, options = {}) {
+ const environment = options.env.NODE_ENV || process.env.NODE_ENV;
+ const plugins = [
+ rollupPluginReplace({ 'process.env.NODE_ENV': JSON.stringify(environment) }),
+ rollupModuleResolver(options),
+ rollupTransfrom(options)
+ ];
+
+ if (isCompat(options.mode)) {
+ plugins.push(rollupCompat(options));
+ }
+
+ if (isProd(options.mode)) {
+ plugins.push(rollupMinify(options));
+ }
+
+ return rollup({
+ input: entry,
+ plugins: plugins,
+ onwarn: rollupWarningOverride,
+ })
+ .then(bundle => {
+ return bundle.generate({
+ amd: { id: options.normalizedModuleName },
+ interop: false,
+ strict: false,
+ format: options.format,
+ globals: options.globals
+ });
+ })
+ .then(result => {
+ return {
+ code: result.code,
+ map: result.map,
+ metadata: mergeMetadata(options.$metadata),
+ rawMetadata: options.$metadata
+ };
+ });
+}
diff --git a/packages/lwc-compiler/src/bundler/__tests__/bundler.spec.ts b/packages/lwc-compiler/src/bundler/__tests__/bundler.spec.ts
deleted file mode 100755
index 4587a44c66..0000000000
--- a/packages/lwc-compiler/src/bundler/__tests__/bundler.spec.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { bundle } from "../bundler";
-import { pretify } from "../../__tests__/utils";
-
-describe('bundler', () => {
- test('throws when invoked without configurations', async () => {
- try {
- const { diagnostics, code, metadata } = await bundle();
- } catch (error) {
- expect(error.message).toBe("Expected options object, received \"undefined\".");
- }
- });
-});
diff --git a/packages/lwc-compiler/src/bundler/__tests__/import-locations.spec.ts b/packages/lwc-compiler/src/bundler/__tests__/import-locations.spec.ts
deleted file mode 100644
index 04cb11b077..0000000000
--- a/packages/lwc-compiler/src/bundler/__tests__/import-locations.spec.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { collectImportLocations } from "../../bundler/import-location-collector";
-
-describe("import locations", () => {
- test("location collector should return empty array if incoming code isn't module", () => {
- const locs = collectImportLocations("debugger");
- expect(locs.length).toBe(0);
- });
-
- test("location collector should return empty array if no imports were specified", () => {
- const src = `define('x-foo', function () {});`
- const locs = collectImportLocations("debugger");
- expect(locs.length).toBe(0);
- });
-
- test("location collector should return location object for each import", () => {
- const src = `define('x-foo', ['x-bar', '@xfoose', 'xy/zoolaf'], function (xBar, xFoose, xZoolaf) {
- xBoo();
- xFoose();
- xZoolaf();
- });`;
- const locs = collectImportLocations(src);
-
- expect(locs.length).toBe(3);
- expect(locs[0]).toMatchObject({
- name: "x-bar",
- location: {
- start: 18,
- length: 5
- }
- });
- expect(locs[1]).toMatchObject({
- name: "@xfoose",
- location: {
- start: 27,
- length: 7
- }
- });
- expect(locs[2]).toMatchObject({
- name: "xy/zoolaf",
- location: {
- start: 38,
- length: 9
- }
- });
- });
-});
diff --git a/packages/lwc-compiler/src/bundler/bundler.ts b/packages/lwc-compiler/src/bundler/bundler.ts
deleted file mode 100755
index d44203b6e5..0000000000
--- a/packages/lwc-compiler/src/bundler/bundler.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import { rollup } from "rollup";
-import * as rollupPluginReplace from "rollup-plugin-replace";
-
-import { MetadataCollector, BundleMetadata } from "./meta-collector";
-import rollupModuleResolver from "../rollup-plugins/module-resolver";
-
-import rollupTransform from "../rollup-plugins/transform";
-import rollupCompat from "../rollup-plugins/compat";
-import rollupMinify from "../rollup-plugins/minify";
-
-import {
- NormalizedCompilerOptions,
- validateNormalizedOptions
-} from "../compiler/options";
-
-import { Diagnostic, DiagnosticLevel } from "../diagnostics/diagnostic";
-
-import { collectImportLocations } from "./import-location-collector";
-
-export interface BundleReport {
- code: string;
- diagnostics: Diagnostic[];
- map: null;
- metadata: BundleMetadata;
-}
-
-interface RollupWarning {
- message: string;
- frame?: string;
- loc?: {
- file: string;
- line: number;
- column: number;
- };
-}
-
-const DEFAULT_FORMAT = "amd";
-
-function handleRollupWarning(diagnostics: Diagnostic[]) {
- return function onwarn({ message, loc }: RollupWarning) {
- const filename = loc && loc.file;
-
- diagnostics.push({
- level: DiagnosticLevel.Warning,
- message,
- filename
- });
- };
-}
-
-export async function bundle(
- options: NormalizedCompilerOptions
-): Promise {
- validateNormalizedOptions(options);
-
- const { outputConfig, name, namespace } = options;
-
- // TODO: remove format option once tests are converted to 'amd' format
- const format = (outputConfig as any).format || DEFAULT_FORMAT;
-
- const diagnostics: Diagnostic[] = [];
-
- const metadataCollector = new MetadataCollector();
-
- const plugins = [
- rollupPluginReplace({
- "process.env.NODE_ENV": JSON.stringify(outputConfig.env.NODE_ENV)
- }),
- rollupModuleResolver({
- metadataCollector,
- options
- }),
- rollupTransform({
- metadataCollector,
- options
- })
- ];
-
- if (outputConfig.compat) {
- plugins.push(rollupCompat(outputConfig.resolveProxyCompat));
- }
-
- if (outputConfig.minify) {
- plugins.push(rollupMinify());
- }
-
- const rollupBundler = await rollup({
- input: name,
- plugins,
- onwarn: handleRollupWarning(diagnostics)
- });
-
- const { code } = await rollupBundler.generate({
- amd: { id: namespace + "-" + name },
- interop: false,
- strict: false,
- format
- });
-
- metadataCollector.collectImportLocations(
- collectImportLocations(code) || []
- );
-
- return {
- diagnostics,
- code,
- map: null,
- metadata: metadataCollector.getMetadata()
- };
-}
diff --git a/packages/lwc-compiler/src/bundler/import-location-collector.ts b/packages/lwc-compiler/src/bundler/import-location-collector.ts
deleted file mode 100644
index a8ef998eec..0000000000
--- a/packages/lwc-compiler/src/bundler/import-location-collector.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { Location } from "../common-interfaces/location";
-
-export interface ModuleImportLocation {
- name: string;
- location: Location;
-}
-
-const MODULE_IMPORT_REGEX = /(?:define\([(['|"][\w-]+['|"],?\s*)(?:\[((?:['|"][@\w-/]+['|"],?\s*)+)\])?,?\s*function/;
-
-export function collectImportLocations(code: string) {
- const matches = new RegExp(MODULE_IMPORT_REGEX).exec(code);
-
- // assert amd
- if (!matches || !matches.length) {
- return [];
- }
-
- const searchSubstring: string = matches[0];
-
- // format: `'x-bar', 'x-foo'`
- const rawImports = matches[1];
- if (!rawImports) {
- return [];
- }
-
- // split result: ["'x-bar', 'x-foo'"]
- const imports = rawImports.split(/,\s*/) || [];
-
- return imports.map((moduleImport) => {
- const normalizedName = moduleImport.replace(/'/g, "");
- const position = searchSubstring.indexOf(normalizedName);
-
- return {
- name: normalizedName,
- location: {
- start: position,
- length: normalizedName.length
- }
- };
- });
-}
diff --git a/packages/lwc-compiler/src/bundler/meta-collector.ts b/packages/lwc-compiler/src/bundler/meta-collector.ts
deleted file mode 100755
index d27445562f..0000000000
--- a/packages/lwc-compiler/src/bundler/meta-collector.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import {
- ApiDecorator,
- TrackDecorator,
- WireDecorator
-} from "babel-plugin-transform-lwc-class";
-
-import { ModuleImportLocation } from "./import-location-collector";
-
-export type MetadataDecorators = Array<
- ApiDecorator | TrackDecorator | WireDecorator
->;
-
-export interface BundleMetadata {
- decorators: MetadataDecorators;
- importLocations: ModuleImportLocation[];
-}
-
-export class MetadataCollector {
- private decorators: Array<
- ApiDecorator | TrackDecorator | WireDecorator
- > = [];
- private importLocations: ModuleImportLocation[] = [];
-
- public collectDecorator(
- decorator: ApiDecorator | TrackDecorator | WireDecorator
- ) {
- this.decorators.push(decorator);
- }
-
- public collectImportLocations(importLocations: ModuleImportLocation[]) {
- this.importLocations.push(...importLocations);
- }
-
- public getMetadata(): BundleMetadata {
- return {
- decorators: this.decorators,
- importLocations: this.importLocations
- };
- }
-}
diff --git a/packages/lwc-compiler/src/common-interfaces/location.ts b/packages/lwc-compiler/src/common-interfaces/location.ts
deleted file mode 100644
index e5f3ba043d..0000000000
--- a/packages/lwc-compiler/src/common-interfaces/location.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export interface Location {
- /** 0-base character index in the file */
- start: number;
-
- /** Number of character after the start index */
- length: number;
-}
diff --git a/packages/lwc-compiler/src/compiler/__tests__/modes.spec.ts b/packages/lwc-compiler/src/compiler/__tests__/modes.spec.ts
deleted file mode 100644
index 7b68b10f6f..0000000000
--- a/packages/lwc-compiler/src/compiler/__tests__/modes.spec.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { readFile } from "fs";
-import { compile } from "../../index";
-import { fixturePath, readFixture, pretify } from "../../__tests__/utils";
-
-const NODE_ENV_CONFIG = {
- name: "node_env",
- namespace: "x",
- files: {
- "node_env.js": readFixture("node_env/node_env.js"),
- "node_env.html": readFixture("node_env/node_env.html")
- },
- outputConfig: { format: "es" }
-};
-
-describe("node env", function() {
- it('sets env.NODE_ENV to "development" by default', async () => {
- const config = {
- name: "foo",
- namespace: "x",
- files: {
- "foo.js": "export const env = process.env.NODE_ENV"
- },
- outputConfig: { format: "es" }
- };
- const { result: { code, metadata } } = await compile(config);
-
- expect(pretify(code)).toBe(
- 'const env = "development";\nexport { env };'
- );
- });
-
- it("removes production code when NODE_ENV option is production", async () => {
- const config = {
- ...NODE_ENV_CONFIG,
- outputConfig: { format: "es", env: { NODE_ENV: "production" } }
- };
- const { result: { code, metadata } } = await compile(config);
-
- expect(pretify(code)).toBe(
- pretify(readFixture("expected-node-env-prod.js"))
- );
- });
-
- it("does not remove production code when in NODE_ENV option is development", async () => {
- const config = {
- ...NODE_ENV_CONFIG,
- outputConfig: { format: "es", env: { NODE_ENV: "development" } }
- };
- const { result: { code, metadata } } = await compile(config);
-
- expect(pretify(code)).toBe(
- pretify(readFixture("expected-node-env-dev.js"))
- );
- });
-});
diff --git a/packages/lwc-compiler/src/compiler/__tests__/options.spec.ts b/packages/lwc-compiler/src/compiler/__tests__/options.spec.ts
deleted file mode 100644
index ba3ba842f7..0000000000
--- a/packages/lwc-compiler/src/compiler/__tests__/options.spec.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import { compile } from "../compiler";
-import { pretify, readFixture } from "../../__tests__/utils";
-
-const VALID_CONFIG = {
- outputConfig: {
- env: {},
- minify: false,
- compat: false,
- format: "amd"
- },
- name: "class_and_template",
- namespace: "x",
- files: {
- "class_and_template.js": readFixture(
- "class_and_template/class_and_template.js"
- ),
- "class_and_template.html": readFixture(
- "class_and_template/class_and_template.html"
- )
- }
-};
-
-describe("compiler options", () => {
- it("should validate presence of options", async () => {
- await expect(compile()).rejects.toMatchObject({
- message: 'Expected options object, received "undefined".'
- });
- });
-
- it("should validate bundle name option", async () => {
- await expect(compile({})).rejects.toMatchObject({
- message: 'Expected a string for name, received "undefined".'
- });
- });
-
- it("should validate bundle namespace option", async () => {
- await expect(compile({ name: "foo" })).rejects.toMatchObject({
- message: 'Expected a string for namespace, received "undefined".'
- });
- });
-
- it("should validate presence of files option", async () => {
- await expect(
- compile({
- name: "/x/foo/foo.js",
- namespace: "x",
- files: {}
- })
- ).rejects.toMatchObject({
- message: "Expected an object with files to be compiled."
- });
- });
-
- it("should validate files option value type", async () => {
- await expect(
- compile({
- name: "foo",
- namespace: "x",
- files: {
- "foo.js": true
- }
- })
- ).rejects.toMatchObject({
- message:
- 'Unexpected file content for "foo.js". Expected a string, received "true".'
- });
- });
-
- it("should validate outputConfig.minify", async () => {
- await expect(
- compile({
- name: "foo",
- namespace: "x",
- files: { x: "foo" },
- outputConfig: {
- minify: "true"
- }
- })
- ).rejects.toMatchObject({
- message:
- 'Expected a boolean for outputConfig.minify, received "true".'
- });
- });
-
- it("should validate outputConfig.compat", async () => {
- await expect(
- compile({
- name: "foo",
- namespace: "x",
- files: { x: "foo" },
- outputConfig: {
- compat: "true"
- }
- })
- ).rejects.toMatchObject({
- message:
- 'Expected a boolean for outputConfig.compat, received "true".'
- });
- });
-});
diff --git a/packages/lwc-compiler/src/compiler/__tests__/result.spec.ts b/packages/lwc-compiler/src/compiler/__tests__/result.spec.ts
deleted file mode 100755
index 3426ee432e..0000000000
--- a/packages/lwc-compiler/src/compiler/__tests__/result.spec.ts
+++ /dev/null
@@ -1,169 +0,0 @@
-import { compile } from "../compiler";
-import { pretify, readFixture } from "../../__tests__/utils";
-
-const VALID_CONFIG = {
- outputConfig: {
- env: {},
- minify: false,
- compat: false,
- format: "amd"
- },
- name: "class_and_template",
- namespace: "x",
- files: {
- "class_and_template.js": readFixture(
- "class_and_template/class_and_template.js"
- ),
- "class_and_template.html": readFixture(
- "class_and_template/class_and_template.html"
- )
- }
-};
-
-describe("compiler result", () => {
- test("compiler should return bundle result default output configuration ", async () => {
- const noOutputConfig = { ...VALID_CONFIG, outputConfig: undefined };
- const { result: { outputConfig } } = await compile(noOutputConfig);
- expect(outputConfig).toMatchObject({
- env: {
- NODE_ENV: "development"
- },
- minify: false,
- compat: false
- });
- });
- test("compiler should return bundle result with normalized DEV output config", async () => {
- const config = Object.assign({}, VALID_CONFIG, {
- outputConfig: {
- minify: false,
- compat: false
- }
- });
- const { result: { outputConfig } } = await compile(config);
- expect(outputConfig).toMatchObject({
- env: {
- NODE_ENV: "development"
- },
- minify: false,
- compat: false
- });
- });
- test("compiler should return bundle result with normalized PROD output config", async () => {
- const config = Object.assign({}, VALID_CONFIG, {
- outputConfig: {
- minify: true,
- compat: false,
- env: {
- NODE_ENV: "production"
- }
- }
- });
- const { result: { outputConfig } } = await compile(config);
- expect(outputConfig).toMatchObject({
- env: {
- NODE_ENV: "production"
- },
- minify: true,
- compat: false
- });
- });
- test("compiler should return bundle result with normalized COMPAT output config", async () => {
- const config = Object.assign({}, VALID_CONFIG, {
- outputConfig: {
- minify: false,
- compat: true
- }
- });
- const { result: { outputConfig } } = await compile(config);
- expect(outputConfig).toMatchObject({
- env: {
- NODE_ENV: "development"
- },
- minify: false,
- compat: true
- });
- });
- test("compiler should return bundle result with normalized PROD_COMPAT output config", async () => {
- const config = Object.assign({}, VALID_CONFIG, {
- outputConfig: {
- minify: false,
- compat: true,
- env: {
- NODE_ENV: "production"
- }
- }
- });
- const { result: { outputConfig } } = await compile(config);
- expect(outputConfig).toMatchObject({
- env: {
- NODE_ENV: "production"
- },
- minify: false,
- compat: true
- });
- });
- test("should return output object with expected properties", async () => {
- const output = await compile(VALID_CONFIG);
- const { success, diagnostics, result, version } = output;
- const { code, metadata } = result;
-
- expect(code).toBeDefined();
- expect(diagnostics).toBeDefined();
- expect(version).toBeDefined();
- expect(metadata).toBeDefined();
- expect(success).toBeDefined();
- });
-});
-
-describe("comiler metadata", () => {
- it("decorators and import locations", async () => {
- const { result: { code, metadata } } = await compile({
- name: "foo",
- namespace: "x",
- files: {
- "foo.js": readFixture("metadata/metadata.js"),
- "foo.html": readFixture("metadata/metadata.html")
- },
- outputConfig: { format: "es" }
- });
-
- expect(pretify(code)).toBe(
- pretify(readFixture("expected-sources-metadata.js"))
- );
-
- expect(metadata).toEqual({
- decorators: [
- {
- type: "api",
- targets: [
- { type: "property", name: "publicProp" },
- { type: "method", name: "publicMethod" }
- ]
- },
- {
- type: "wire",
- targets: [
- {
- type: "property",
- adapter: { name: "getTodo", reference: "todo" },
- name: "wiredProp",
- params: {},
- static: {}
- },
- {
- type: "method",
- adapter: {
- name: "getHello",
- reference: "@schema/foo.bar"
- },
- name: "wiredMethod",
- params: { name: "publicProp" },
- static: { fields: ["one", "two"] }
- }
- ]
- }
- ],
- importLocations: []
- });
- });
-});
diff --git a/packages/lwc-compiler/src/compiler/__tests__/stylesheet.spec.ts b/packages/lwc-compiler/src/compiler/__tests__/stylesheet.spec.ts
deleted file mode 100644
index d8505c8009..0000000000
--- a/packages/lwc-compiler/src/compiler/__tests__/stylesheet.spec.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { readFile } from "fs";
-import { compile } from "../../index";
-import { fixturePath, readFixture, pretify } from "../../__tests__/utils";
-
-describe("stylesheet", () => {
- it("should import the associated stylesheet by default", async () => {
- const { result: { code } } = await compile({
- name: "styled",
- namespace: "x",
- files: {
- "styled.js": readFixture("namespaced_folder/styled/styled.js"),
- "styled.html": readFixture(
- "namespaced_folder/styled/styled.html"
- ),
- "styled.css": readFixture("namespaced_folder/styled/styled.css")
- },
- outputConfig: { format: "es" }
- });
- expect(pretify(code)).toBe(pretify(readFixture("expected-styled.js")));
- });
-
- it("should import compress css in prod mode", async () => {
- const { result: { code } } = await compile({
- name: "styled",
- namespace: "x",
- files: {
- "styled.js": readFixture("namespaced_folder/styled/styled.js"),
- "styled.html": readFixture(
- "namespaced_folder/styled/styled.html"
- ),
- "styled.css": readFixture("namespaced_folder/styled/styled.css")
- },
- outputConfig: { format: "es", minify: true }
- });
- expect(pretify(code)).toBe(
- pretify(readFixture("expected-styled-prod.js"))
- );
- });
-});
diff --git a/packages/lwc-compiler/src/compiler/compiler.ts b/packages/lwc-compiler/src/compiler/compiler.ts
deleted file mode 100755
index 33fb145aec..0000000000
--- a/packages/lwc-compiler/src/compiler/compiler.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { bundle } from "../bundler/bundler";
-import { BundleMetadata } from "../bundler/meta-collector";
-import { Diagnostic, DiagnosticLevel } from "../diagnostics/diagnostic";
-import { CompilerOptions, validateOptions, normalizeOptions, NormalizedOutputConfig } from "./options";
-import { version } from '../index';
-
-export { default as templateCompiler } from "lwc-template-compiler";
-
-export interface CompilerOutput {
- success: boolean;
- diagnostics: Diagnostic[];
- result?: BundleResult;
- version: string;
-}
-
-export interface BundleResult {
- code: string;
- map: null;
- metadata: BundleMetadata;
- outputConfig: NormalizedOutputConfig;
-}
-
-export async function compile(
- options: CompilerOptions
-): Promise {
- validateOptions(options);
- const normalizedOptions = normalizeOptions(options);
-
- let result: BundleResult | undefined;
- const diagnostics: Diagnostic[] = [];
-
- const {
- diagnostics: bundleDiagnostics,
- code,
- metadata,
- } = await bundle(normalizedOptions);
-
- diagnostics.push(...bundleDiagnostics);
-
- if (!hasError(diagnostics)) {
- result = {
- code,
- map: null,
- metadata,
- outputConfig: normalizedOptions.outputConfig,
- };
- }
- return {
- version,
- success: !hasError(diagnostics),
- diagnostics,
- result
- };
-}
-
-function hasError(diagnostics: Diagnostic[]) {
- return diagnostics.some(d => {
- return d.level <= DiagnosticLevel.Error;
- });
-}
diff --git a/packages/lwc-compiler/src/compiler/options.ts b/packages/lwc-compiler/src/compiler/options.ts
deleted file mode 100755
index e63fbd77c2..0000000000
--- a/packages/lwc-compiler/src/compiler/options.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import { isBoolean, isString, isUndefined } from "../utils";
-
-const DEFAULT_OUTPUT_CONFIG = {
- env: {
- NODE_ENV: "development"
- },
- minify: false,
- compat: false
-};
-
-export type OutputProxyCompatConfig =
- | { global: string }
- | { module: string }
- | { independent: string };
-
-export interface OutputConfig {
- env?: { [name: string]: string };
- compat?: boolean;
- minify?: boolean;
- resolveProxyCompat?: OutputProxyCompatConfig;
-}
-
-export interface BundleFiles {
- [filename: string]: string;
-}
-
-export interface CompilerOptions {
- name: string;
- namespace: string;
- files: BundleFiles;
- outputConfig?: OutputConfig;
-}
-
-export interface NormalizedCompilerOptions extends CompilerOptions {
- outputConfig: NormalizedOutputConfig;
-}
-
-export interface NormalizedOutputConfig extends OutputConfig {
- compat: boolean;
- minify: boolean;
- env: {
- [name: string]: string;
- };
-}
-
-export function validateNormalizedOptions(options: NormalizedCompilerOptions) {
- validateOptions(options);
- validateOutputConfig(options.outputConfig);
-}
-
-export function validateOptions(options: CompilerOptions) {
- if (isUndefined(options)) {
- throw new TypeError(`Expected options object, received "${options}".`);
- }
-
- if (!isString(options.name)) {
- throw new TypeError(
- `Expected a string for name, received "${options.name}".`
- );
- }
-
- if (!isString(options.namespace)) {
- throw new TypeError(
- `Expected a string for namespace, received "${options.namespace}".`
- );
- }
-
- if (isUndefined(options.files) || !Object.keys(options.files).length) {
- throw new TypeError(`Expected an object with files to be compiled.`);
- }
-
- for (const key of Object.keys(options.files)) {
- const value = options.files[key];
- if (isUndefined(value) || !isString(value)) {
- throw new TypeError(
- `Unexpected file content for "${key}". Expected a string, received "${value}".`
- );
- }
- }
-
- if (!isUndefined(options.outputConfig)) {
- validateOutputConfig(options.outputConfig);
- }
-}
-
-function validateOutputConfig(config: OutputConfig) {
- if (!isUndefined(config.minify) && !isBoolean(config.minify)) {
- throw new TypeError(
- `Expected a boolean for outputConfig.minify, received "${
- config.minify
- }".`
- );
- }
-
- if (!isUndefined(config.compat) && !isBoolean(config.compat)) {
- throw new TypeError(
- `Expected a boolean for outputConfig.compat, received "${
- config.compat
- }".`
- );
- }
-}
-
-export function normalizeOptions(
- options: CompilerOptions
-): NormalizedCompilerOptions {
- const outputConfig: NormalizedOutputConfig = {
- ...DEFAULT_OUTPUT_CONFIG,
- ...options.outputConfig
- };
-
- return {
- ...options,
- outputConfig
- };
-}
diff --git a/packages/lwc-compiler/src/diagnostics/diagnostic-collector.ts b/packages/lwc-compiler/src/diagnostics/diagnostic-collector.ts
new file mode 100644
index 0000000000..ee8074bbba
--- /dev/null
+++ b/packages/lwc-compiler/src/diagnostics/diagnostic-collector.ts
@@ -0,0 +1,33 @@
+import { Diagnostic, DiagnosticLevel } from './diagnostic';
+
+export class DiagnosticCollector {
+ private diagnostics: Diagnostic[] = [];
+
+ constructor(diagnostics?: Diagnostic[]) {
+ if (diagnostics) {
+ this.addAll(diagnostics);
+ }
+ }
+ public getAll() {
+ return this.diagnostics;
+ }
+
+ public addAll(items: Diagnostic[]) {
+ if (!Array.isArray(items)) {
+ return;
+ }
+ for (const item of items) {
+ this.add(item);
+ }
+ }
+
+ public add(item: Diagnostic) {
+ this.diagnostics.push(item);
+ }
+
+ public hasError() {
+ return this.diagnostics.some(d => {
+ return d.level <= DiagnosticLevel.Error;
+ });
+ }
+}
diff --git a/packages/lwc-compiler/src/diagnostics/diagnostic.ts b/packages/lwc-compiler/src/diagnostics/diagnostic.ts
old mode 100755
new mode 100644
index 3a03bbf246..3fdc09169d
--- a/packages/lwc-compiler/src/diagnostics/diagnostic.ts
+++ b/packages/lwc-compiler/src/diagnostics/diagnostic.ts
@@ -1,15 +1,13 @@
-import { Location } from '../common-interfaces/location';
-
export interface Diagnostic {
/** Level of the diagnostic */
level: DiagnosticLevel;
+ /** Relative path location of the file in the bundle. */
+ filename: string;
+
/** Error messages that should be outputed */
message: string;
- /** Relative path location of the file in the bundle. */
- filename?: string;
-
/**
* Location in the code affected by the diagnostic.
* This field is optional, for example when the compiler throws an uncaught exception.
@@ -27,3 +25,11 @@ export enum DiagnosticLevel {
/** Logging messages */
Log = 3,
}
+
+export interface Location {
+ /** 0-base character index in the file */
+ start: number;
+
+ /** Number of character after the start index */
+ length: number;
+}
diff --git a/packages/lwc-compiler/src/index.js b/packages/lwc-compiler/src/index.js
new file mode 100644
index 0000000000..1c0dc4cfbc
--- /dev/null
+++ b/packages/lwc-compiler/src/index.js
@@ -0,0 +1,159 @@
+import * as path from 'path';
+
+import bundle from './bundle';
+import transformFile from './transform';
+
+import { MODES, ALL_MODES, isProd } from './modes';
+import { zipObject, isUndefined, isString } from './utils';
+
+import * as replacePlugin from "rollup-plugin-replace";
+import fsModuleResolver from './module-resolvers/fs';
+import inMemoryModuleResolver from './module-resolvers/in-memory';
+import minifyPlugin from "./rollup-plugins/minify";
+
+export { default as templateCompiler } from 'lwc-template-compiler';
+
+const DEFAULT_NAMESPACE = 'x';
+const DEFAULT_TRANSFORM_OPTIONS = { mode: MODES.DEV };
+
+const DEFAULT_COMPILE_OPTIONS = {
+ format: 'es',
+ mode: MODES.DEV,
+ mapNamespaceFromPath: false,
+ env: {},
+ resolveProxyCompat: {
+ independent: 'proxy-compat',
+ },
+};
+
+export function compile(entry, options = {}) {
+ if (isUndefined(entry) || !isString(entry)) {
+ throw new Error(
+ `Expected a string for entry. Received instead ${entry}`,
+ );
+ }
+
+ entry = normalizeEntryPath(entry);
+ options = Object.assign({ entry }, DEFAULT_COMPILE_OPTIONS, options);
+
+ const acceptedModes = Object.keys(MODES).map(mode => MODES[mode]);
+ if (!acceptedModes.includes(options.mode)) {
+ throw new Error(
+ `Expected a mode in ${acceptedModes.join(
+ ', ',
+ )}. Received instead ${options.mode}`,
+ );
+ }
+
+ // Extract component namespace and name and add it to option
+ // TODO: rename the componentName and componentNamespace APIs, to moduleName and moduleNamespace,
+ // not all the modules are components.
+ const { name, namespace, normalizedName } = getNormalizedName(entry, options);
+ options.moduleName = name;
+ options.moduleNamespace = namespace;
+ options.normalizedModuleName = normalizedName;
+
+ // Add extra properties needed for the compilation
+ // TODO: provide proper abstraction instead of stuffing the options object
+ options.$metadata = {};
+ options.moduleResolver = isUndefined(options.sources)
+ ? fsModuleResolver()
+ : inMemoryModuleResolver(options);
+
+ if (options.mode !== MODES.ALL) {
+ return bundle(entry, options);
+ } else {
+ // Compile the bundle in all modes at the same time
+
+ // TODO: should this be exposed at the compiler level or should the caller call the compiler in all the modes ?
+ // Because the caller has probalby a better understanding of the current architecture, it can leverage multiple
+ // processor at the same time!
+ return Promise.all(
+ ALL_MODES.map(mode =>
+ compile(entry, Object.assign({}, options, { mode })),
+ ),
+ ).then(results => {
+ return zipObject(ALL_MODES, results);
+ });
+ }
+}
+
+export function transform(src, id, options) {
+ if (!isString(src)) {
+ throw new Error(`Expect a string for source. Received ${src}`);
+ }
+
+ if (!isString(id)) {
+ throw new Error(`Expect a string for id. Received ${id}`);
+ }
+
+ options = Object.assign({}, DEFAULT_TRANSFORM_OPTIONS, options);
+ return transformFile(src, id, options);
+}
+
+export function transformBundle(src, options) {
+ const mode = options.mode;
+
+ if (isProd(mode)) {
+ const rollupReplace = replacePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') });
+ const rollupMinify = minifyPlugin(options);
+ const resultReplace = rollupReplace.transform(src, '$__tmpBundleSrc');
+ const result = rollupMinify.transformBundle(resultReplace ? resultReplace.code : src);
+
+ src = result.code;
+ }
+
+ return src;
+}
+
+/**
+ * Takes a module location and returns it's entry point:
+ * '/foo/bar' => '/foo/bar/bar'
+ * '/foo/bar/bar.js' => '/foo/bar/bar.js'
+ *
+ * @param {string} fileName
+ */
+function normalizeEntryPath(fileName) {
+ fileName = path.normalize(fileName.replace(/\/$/, ''));
+ const ext = path.extname(fileName);
+ return ext
+ ? fileName
+ : path.join(fileName, fileName.split(path.sep).pop() + ext);
+}
+
+/**
+ * Names and namespace mapping:
+ * 'foo.js' => ns: default, name: foo
+ * '.../foo/foo.js' => ns: default, name: foo
+ * '.../myns/foo/foo.js' => ns: myns, name: foo
+ */
+function getNormalizedName(fileName,{ componentName, componentNamespace, mapNamespaceFromPath }) {
+ const ext = path.extname(fileName);
+ const parts = fileName.split(path.sep);
+
+ const name = componentName || path.basename(parts.pop(), ext);
+
+ let namespace;
+ if (!isUndefined(componentNamespace)) {
+ namespace = componentNamespace;
+ } else {
+ namespace = name.indexOf('-') === -1 ? DEFAULT_NAMESPACE : null;
+
+ let tmpNs = parts.pop();
+ if (tmpNs === name) {
+ tmpNs = parts.pop();
+ }
+ // If mapping folder structure override namespace
+ if (tmpNs && mapNamespaceFromPath) {
+ namespace = tmpNs;
+ }
+ }
+
+ return {
+ name,
+ namespace,
+ normalizedName: [namespace, name].join('-'),
+ };
+}
+
+export const version = '__VERSION__';
diff --git a/packages/lwc-compiler/src/index.ts b/packages/lwc-compiler/src/index.ts
deleted file mode 100755
index 2890fe7902..0000000000
--- a/packages/lwc-compiler/src/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export { compile } from './compiler/compiler';
-export { transform } from './transformers/transformer';
-export const version = '__VERSION__';
diff --git a/packages/lwc-compiler/src/lwc-bundle.ts b/packages/lwc-compiler/src/lwc-bundle.ts
new file mode 100644
index 0000000000..35ffce15d3
--- /dev/null
+++ b/packages/lwc-compiler/src/lwc-bundle.ts
@@ -0,0 +1,4 @@
+export interface LwcBundle {
+ entry: string;
+ sources: [{ filename: string }];
+}
diff --git a/packages/lwc-compiler/src/modes.js b/packages/lwc-compiler/src/modes.js
new file mode 100644
index 0000000000..74eff5d864
--- /dev/null
+++ b/packages/lwc-compiler/src/modes.js
@@ -0,0 +1,32 @@
+/** Available compilation modes */
+export const MODES = {
+ DEV: 'dev',
+ PROD: 'prod',
+ COMPAT: 'compat',
+ PROD_COMPAT: 'prod_compat',
+ ALL: 'all',
+};
+
+/** List of all the modes */
+export const ALL_MODES = [
+ MODES.DEV,
+ MODES.PROD,
+ MODES.COMPAT,
+ MODES.PROD_COMPAT,
+];
+
+/**
+ * Returns true if the passed mode is a PROD mode
+ * @param {string} mode
+ */
+export function isProd(mode) {
+ return mode === MODES.PROD || mode === MODES.PROD_COMPAT;
+}
+
+/**
+ * Returns true if the passed mode is a COMPAT mode
+ * @param {string} mode
+ */
+export function isCompat(mode) {
+ return mode === MODES.COMPAT || mode === MODES.PROD_COMPAT;
+}
diff --git a/packages/lwc-compiler/src/module-resolvers/fs.js b/packages/lwc-compiler/src/module-resolvers/fs.js
new file mode 100644
index 0000000000..67a30d5fe5
--- /dev/null
+++ b/packages/lwc-compiler/src/module-resolvers/fs.js
@@ -0,0 +1,23 @@
+import * as fs from 'fs';
+
+const DEFAULT_ENCODING = 'utf-8';
+
+export default function() {
+ return {
+ fileExists(fileName) {
+ return new Promise(resolve =>
+ fs.access(fileName, fs.constants.F_OK, err => {
+ return err ? resolve(false) : resolve(true);
+ })
+ );
+ },
+
+ readFile(fileName) {
+ return new Promise((resolve, reject) =>
+ fs.readFile(fileName, DEFAULT_ENCODING, (err, data) => {
+ return err ? reject(err) : resolve(data);
+ })
+ );
+ },
+ };
+}
diff --git a/packages/lwc-compiler/src/module-resolvers/in-memory.js b/packages/lwc-compiler/src/module-resolvers/in-memory.js
new file mode 100644
index 0000000000..d137a552c5
--- /dev/null
+++ b/packages/lwc-compiler/src/module-resolvers/in-memory.js
@@ -0,0 +1,25 @@
+export default function({ sources } = {}) {
+ for (let key of Object.keys(sources)) {
+ if (sources[key] == undefined || typeof sources[key] !== 'string') {
+ throw new Error(
+ `in-memory module resolution expects values to be string. Received ${sources[
+ key
+ ]} for key ${key}`
+ );
+ }
+ }
+
+ const fileExists = fileName => sources.hasOwnProperty(fileName);
+
+ return {
+ fileExists(fileName) {
+ return Promise.resolve(fileExists(fileName));
+ },
+
+ readFile(fileName) {
+ return fileExists(fileName)
+ ? Promise.resolve(sources[fileName])
+ : Promise.reject(new Error(`No such file ${fileName}`));
+ },
+ };
+}
diff --git a/packages/lwc-compiler/src/references/__tests__/css.spec.ts b/packages/lwc-compiler/src/references/__tests__/css.spec.ts
new file mode 100644
index 0000000000..ff903f4ed5
--- /dev/null
+++ b/packages/lwc-compiler/src/references/__tests__/css.spec.ts
@@ -0,0 +1,342 @@
+import { getReferences } from '../../references/css';
+
+test('single selector', () => {
+ expect(getReferences(`x-foo { color: red; }`, 'test.js')).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 0,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('single selector with attributes', () => {
+ expect(
+ getReferences(`x-foo[title="Hello"] { color: red; }`, 'test.js'),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 0,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('selector chain', () => {
+ expect(getReferences(`header x-foo { color: red; }`, 'test.js')).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 7,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('selector list', () => {
+ expect(
+ getReferences(`header x-foo, div, x-bar { color: red; }`, 'test.js'),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 7,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 19,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('multiline selector list', () => {
+ expect(getReferences(`x-foo,\nx-bar { color: red; }`, 'test.js')).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 0,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 7,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('ugly selector list', () => {
+ expect(
+ getReferences(
+ ` x-foo, p .foo, \nx-bar {\n color : red ;\n }`,
+ 'test.js',
+ ),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 6,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 28,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('multiple rules', () => {
+ expect(
+ getReferences(
+ `x-foo {\ncolor: red;\n }\n \nx-bar {\ncolor: red;\n}`,
+ 'test.js',
+ ),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 0,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 25,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+
+test('single selector', () => {
+ expect(getReferences(`x-foo { color: red; }`, 'test.js')).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 0,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('single selector with attributes', () => {
+ expect(
+ getReferences(`x-foo[title="Hello"] { color: red; }`, 'test.js'),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 0,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('selector chain', () => {
+ expect(getReferences(`header x-foo { color: red; }`, 'test.js')).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 7,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('selector list', () => {
+ expect(
+ getReferences(`header x-foo, div, x-bar { color: red; }`, 'test.js'),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 7,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 19,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('multiline selector list', () => {
+ expect(getReferences(`x-foo,\nx-bar { color: red; }`, 'test.js')).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 0,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 7,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('ugly selector list', () => {
+ expect(
+ getReferences(
+ ` x-foo, p .foo, \nx-bar {\n color : red ;\n }`,
+ 'test.js',
+ ),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 6,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 28,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('multiple rules', () => {
+ expect(
+ getReferences(
+ `x-foo {\ncolor: red;\n }\n \nx-bar {\ncolor: red;\n}`,
+ 'test.js',
+ ),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 0,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 25,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
diff --git a/packages/lwc-compiler/src/references/__tests__/html.spec.ts b/packages/lwc-compiler/src/references/__tests__/html.spec.ts
new file mode 100644
index 0000000000..516cedf084
--- /dev/null
+++ b/packages/lwc-compiler/src/references/__tests__/html.spec.ts
@@ -0,0 +1,78 @@
+import { getReferences } from '../../references/html';
+
+test('simple component', () => {
+ expect(
+ getReferences(``, 'test.js'),
+ ).toEqual([
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 11,
+ length: 5,
+ },
+ {
+ start: 19,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
+
+test('nested components', () => {
+ expect(
+ getReferences(
+ ``,
+ 'test.js',
+ ),
+ ).toEqual([
+ {
+ id: 'x-bar',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 18,
+ length: 5,
+ },
+ {
+ start: 26,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-foo',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 11,
+ length: 5,
+ },
+ {
+ start: 34,
+ length: 5,
+ },
+ ],
+ },
+ {
+ id: 'x-baz',
+ file: 'test.js',
+ type: 'component',
+ locations: [
+ {
+ start: 41,
+ length: 5,
+ },
+ {
+ start: 49,
+ length: 5,
+ },
+ ],
+ },
+ ]);
+});
diff --git a/packages/lwc-compiler/src/references/__tests__/javascript.spec.ts b/packages/lwc-compiler/src/references/__tests__/javascript.spec.ts
new file mode 100644
index 0000000000..622b541077
--- /dev/null
+++ b/packages/lwc-compiler/src/references/__tests__/javascript.spec.ts
@@ -0,0 +1,115 @@
+import { getReferences } from '../../references/javascript';
+
+describe('resource-url', () => {
+ test('gather metadata', () => {
+ expect(
+ getReferences(
+ `import resource from '@resource-url/foo';`,
+ 'test.js',
+ ),
+ ).toEqual([
+ {
+ id: 'foo',
+ file: 'test.js',
+ type: 'resourceUrl',
+ locations: [
+ {
+ start: 36,
+ length: 3,
+ },
+ ],
+ },
+ ]);
+ });
+
+ test('errors when using namespaced import', () => {
+ expect(() =>
+ getReferences(
+ `import * as resource from '@resource-url/foo';`,
+ 'test.js',
+ ),
+ ).toThrow('@resource-url modules only support default imports.');
+ });
+
+ test('errors when using a named import', () => {
+ expect(() =>
+ getReferences(
+ `import { resource } from '@resource-url/foo';`,
+ 'test.js',
+ ),
+ ).toThrow('@resource-url modules only support default imports.');
+ });
+});
+
+describe('label', () => {
+ test('gather metadata', () => {
+ expect(
+ getReferences(`import label from '@label/foo';`, 'test.js'),
+ ).toEqual([
+ {
+ id: 'foo',
+ file: 'test.js',
+ type: 'label',
+ locations: [
+ {
+ start: 26,
+ length: 3,
+ },
+ ],
+ },
+ ]);
+ });
+
+ test('errors when using namespaced import', () => {
+ expect(() =>
+ getReferences(`import * as label from '@label/foo';`, 'test.js'),
+ ).toThrow('@label modules only support default imports.');
+ });
+
+ test('errors when using a named import', () => {
+ expect(() =>
+ getReferences(`import { label } from '@label/foo';`, 'test.js'),
+ ).toThrow('@label modules only support default imports.');
+ });
+});
+
+describe('apex', () => {
+ test('gather metadata', () => {
+ expect(
+ getReferences(
+ `import methodA from '@apex/MyClass.methodA';`,
+ 'test.js',
+ ),
+ ).toEqual([
+ {
+ id: 'MyClass.methodA',
+ file: 'test.js',
+ type: 'apexMethod',
+ locations: [
+ {
+ start: 27,
+ length: 15,
+ },
+ ],
+ },
+ ]);
+ });
+
+ test('errors when using namespaced import', () => {
+ expect(() =>
+ getReferences(
+ `import * as MyClass from '@apex/MyClass';`,
+ 'test.js',
+ ),
+ ).toThrow('@apex modules only support default imports.');
+ });
+
+ test('errors when using a default import', () => {
+ expect(() =>
+ getReferences(
+ `import { methodA } from '@apex/MyClass';`,
+ 'test.js',
+ ),
+ ).toThrow('@apex modules only support default imports.');
+ });
+});
diff --git a/packages/lwc-compiler/src/references/css.ts b/packages/lwc-compiler/src/references/css.ts
new file mode 100644
index 0000000000..2e51862b11
--- /dev/null
+++ b/packages/lwc-compiler/src/references/css.ts
@@ -0,0 +1,71 @@
+import { Reference } from './types';
+
+import * as postcss from 'postcss';
+import { Rule } from 'postcss';
+
+import * as postcssSelector from 'postcss-selector-parser';
+import { isTag } from 'postcss-selector-parser';
+
+function isCustomElementSelector(tag: string) {
+ return tag.includes('-');
+}
+
+function getSelectorOffset(rule: Rule, source: string) {
+ // line and column are both 1 based.
+ const { line, column } = rule.source.start!;
+
+ const lines = source.split('\n');
+ const lineOffset = lines
+ .slice(0, line - 1)
+ .reduce((offset, l) => offset + l.length + 1, 0);
+
+ return lineOffset + column - 1;
+}
+
+function getSelectorReferences(
+ selector: string,
+ filename: string,
+ offset: number,
+): Reference[] {
+ const references: Reference[] = [];
+
+ const processor = postcssSelector();
+ const root = processor.astSync(selector, { lossless: true });
+
+ root.walk(node => {
+ if (!isTag(node) || !isCustomElementSelector(node.value)) {
+ return;
+ }
+
+ references.push({
+ id: node.value,
+ type: 'component',
+ file: filename,
+ locations: [
+ {
+ start: offset + node.sourceIndex,
+ length: node.value.length,
+ },
+ ],
+ });
+ });
+
+ return references;
+}
+
+export function getReferences(source: string, filename: string): Reference[] {
+ const references: Reference[] = [];
+
+ const root = postcss.parse(source, { from: filename });
+ root.walkRules(rule => {
+ const selectorOffset = getSelectorOffset(rule, source);
+ const ruleReferences = getSelectorReferences(
+ rule.selector,
+ filename,
+ selectorOffset,
+ );
+ references.push(...ruleReferences);
+ });
+
+ return references;
+}
diff --git a/packages/lwc-compiler/src/references/html.ts b/packages/lwc-compiler/src/references/html.ts
new file mode 100644
index 0000000000..013a48f8b9
--- /dev/null
+++ b/packages/lwc-compiler/src/references/html.ts
@@ -0,0 +1,58 @@
+import { Reference } from './types';
+import { SAXParser } from 'parse5';
+
+function isCustomElement(name: string) {
+ return name.includes('-');
+}
+
+export function getReferences(source: string, filename: string): Reference[] {
+ const parser = new SAXParser({ locationInfo: true });
+
+ const references: Reference[] = [];
+ const stack: Reference[] = [];
+
+ parser.on('startTag', (name, attrs, selfClosing, location) => {
+ if (!isCustomElement(name)) {
+ return;
+ }
+
+ const startTagRef: Reference = {
+ id: name,
+ type: 'component',
+ file: filename,
+ locations: [
+ {
+ // Location offset given by the parser includes the preceding "<"
+ start: location!.startOffset + 1,
+ length: name.length,
+ },
+ ],
+ };
+
+ stack.push(startTagRef);
+ });
+
+ parser.on('endTag', (name, location) => {
+ if (!isCustomElement(name)) {
+ return;
+ }
+
+ const tagRef = stack.pop();
+
+ if (!tagRef) {
+ throw new Error(`Missing matching tack for <${name}>`);
+ }
+
+ tagRef.locations.push({
+ // Location offset given by the parser includes the preceding ""
+ start: location!.startOffset + 2,
+ length: name.length,
+ });
+
+ references.push(tagRef);
+ });
+
+ parser.end(source);
+
+ return references;
+}
diff --git a/packages/lwc-compiler/src/references/javascript.ts b/packages/lwc-compiler/src/references/javascript.ts
new file mode 100644
index 0000000000..49ff7365c5
--- /dev/null
+++ b/packages/lwc-compiler/src/references/javascript.ts
@@ -0,0 +1,156 @@
+import { Reference } from './types';
+import traverse, { NodePath } from 'babel-traverse';
+import * as t from 'babel-types';
+import { parse } from 'babylon';
+
+const APEX_PREFIX = '@apex';
+const LABEL_PREFIX = '@label';
+const RESOURCE_URL_PREFIX = '@resource-url';
+
+export function isGvpSource(prefix: string) {
+ return (source: string) => source.startsWith(`${prefix}/`);
+}
+
+const isApexSource = isGvpSource(APEX_PREFIX);
+const isLabelSource = isGvpSource(LABEL_PREFIX);
+const isResourceUrlSource = isGvpSource(RESOURCE_URL_PREFIX);
+
+function getGvpId(path: NodePath) {
+ const { value } = path.node.source;
+ const res = /^@[\w-]+\/(.+)$/.exec(value);
+
+ if (!res) {
+ throw new Error(`Unexpected GVP source for ${value}`);
+ }
+
+ return res[1];
+}
+
+function assertOnlyDefaultImport(
+ path: NodePath,
+ error: string,
+) {
+ const hasNamedImport = path.node.specifiers.some(
+ node => !t.isImportDefaultSpecifier(node),
+ );
+
+ if (hasNamedImport) {
+ // TODO: convert into diagnostic
+ throw new Error(error);
+ }
+}
+
+function getResourceReferences(
+ path: NodePath,
+ filename: string,
+): Reference[] {
+ assertOnlyDefaultImport(
+ path,
+ `${RESOURCE_URL_PREFIX} modules only support default imports.`,
+ );
+
+ const id = getGvpId(path);
+ const { source } = path.node;
+
+ return [
+ {
+ id,
+ type: 'resourceUrl',
+ file: filename,
+ locations: [
+ {
+ start: source.start + RESOURCE_URL_PREFIX.length + 2,
+ length: id.length,
+ },
+ ],
+ },
+ ];
+}
+
+function getLabelReferences(
+ path: NodePath,
+ filename: string,
+): Reference[] {
+ assertOnlyDefaultImport(
+ path,
+ `${LABEL_PREFIX} modules only support default imports.`,
+ );
+
+ const id = getGvpId(path);
+ const { source } = path.node;
+
+ return [
+ {
+ id,
+ type: 'label',
+ file: filename,
+ locations: [
+ {
+ start: source.start + LABEL_PREFIX.length + 2,
+ length: id.length,
+ },
+ ],
+ },
+ ];
+}
+
+function getApexReferences(
+ path: NodePath,
+ filename: string,
+): Reference[] {
+ assertOnlyDefaultImport(
+ path,
+ `${APEX_PREFIX} modules only support default imports.`,
+ );
+
+ const id = getGvpId(path);
+ const { source } = path.node;
+
+ return [
+ {
+ id,
+ type: 'apexMethod',
+ file: filename,
+ locations: [
+ {
+ start: source.start + APEX_PREFIX.length + 2,
+ length: id.length,
+ },
+ ],
+ },
+ ];
+}
+
+function sfdcReferencesVisitor(references: Reference[], filename: string) {
+ return {
+ ImportDeclaration(path: NodePath) {
+ const { value } = path.node.source;
+
+ let importReferences: Reference[] = [];
+
+ if (isResourceUrlSource(value)) {
+ importReferences = getResourceReferences(path, filename);
+ } else if (isLabelSource(value)) {
+ importReferences = getLabelReferences(path, filename);
+ } else if (isApexSource(value)) {
+ importReferences = getApexReferences(path, filename);
+ }
+
+ references.push(...importReferences);
+ },
+ };
+}
+
+export function getReferences(source: string, filename: string): Reference[] {
+ const references: Reference[] = [];
+
+ const ast = parse(source, {
+ sourceFilename: filename,
+ sourceType: 'module',
+ plugins: ['classProperties', 'decorators', 'objectRestSpread'],
+ });
+
+ traverse(ast, sfdcReferencesVisitor(references, filename));
+
+ return references;
+}
diff --git a/packages/lwc-compiler/src/references/references.ts b/packages/lwc-compiler/src/references/references.ts
new file mode 100644
index 0000000000..a150030748
--- /dev/null
+++ b/packages/lwc-compiler/src/references/references.ts
@@ -0,0 +1,41 @@
+import * as path from 'path';
+
+import { getReferences as getCssReferences } from './css';
+import { getReferences as getHtmlReferences } from './html';
+import { getReferences as getJsReferences } from './javascript';
+import { Reference } from './types';
+
+import { LwcBundle } from '../lwc-bundle';
+
+export function getBundleReferences(bundle: LwcBundle): Reference[] {
+ if (!bundle || !bundle.sources) {
+ return [];
+ }
+ // TODO: ts is complaining if [filename, source] is used instead of entry
+ return Object.entries(bundle.sources).reduce(
+ (refs: Reference[], entry: any) => {
+ const filename = entry[0];
+ const source = entry[1];
+ return [...refs, ...getFileReferences(source, filename)];
+ },
+ [],
+ );
+}
+
+export function getFileReferences(
+ source: string,
+ filename: string,
+): Reference[] {
+ const ext = path.extname(filename);
+
+ switch (ext) {
+ case '.html':
+ return getHtmlReferences(source, filename);
+ case '.js':
+ return getJsReferences(source, filename);
+ case '.css':
+ return getCssReferences(source, filename);
+ default:
+ return [];
+ }
+}
diff --git a/packages/lwc-compiler/src/references/types.ts b/packages/lwc-compiler/src/references/types.ts
new file mode 100644
index 0000000000..2fb84c08b9
--- /dev/null
+++ b/packages/lwc-compiler/src/references/types.ts
@@ -0,0 +1,11 @@
+export declare type ReferenceType = 'resourceUrl' | 'label' | 'apexClass' | 'apexMethod' | 'sobjectClass' | 'sobjectField' | 'component';
+export interface ReferenceLocation {
+ start: number;
+ length: number;
+}
+export interface Reference {
+ type: ReferenceType;
+ id: string;
+ file: string;
+ locations: ReferenceLocation[];
+}
diff --git a/packages/lwc-compiler/src/rollup-plugins/compat.js b/packages/lwc-compiler/src/rollup-plugins/compat.js
new file mode 100644
index 0000000000..0c2b1f84de
--- /dev/null
+++ b/packages/lwc-compiler/src/rollup-plugins/compat.js
@@ -0,0 +1,24 @@
+import { transform } from '@babel/core';
+import presetCompat from 'babel-preset-compat';
+import { BABEL_CONFIG_BASE } from '../babel-plugins';
+
+/**
+ * Rollup plugin transforms for compat mode:
+ * - Proxy compat
+ * - ES2015+ transpilation to ES5
+ */
+export default function({ resolveProxyCompat }) {
+ const config = Object.assign({}, BABEL_CONFIG_BASE, {
+ presets: [
+ [presetCompat, { proxy: true, resolveProxyCompat }],
+ ],
+ });
+
+ return {
+ name: 'compat',
+ transform(src) {
+ const { code, map } = transform(src, config);
+ return { code, map };
+ },
+ };
+}
diff --git a/packages/lwc-compiler/src/rollup-plugins/compat.ts b/packages/lwc-compiler/src/rollup-plugins/compat.ts
deleted file mode 100755
index b41bd244c0..0000000000
--- a/packages/lwc-compiler/src/rollup-plugins/compat.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as babel from '@babel/core';
-import * as presetCompat from 'babel-preset-compat';
-import { BABEL_CONFIG_BASE } from '../babel-plugins';
-import { OutputProxyCompatConfig } from "../compiler/options";
-
-export default function(proxyCompatOption: OutputProxyCompatConfig | undefined) {
- const config = Object.assign({}, BABEL_CONFIG_BASE, {
- presets: [
- [presetCompat, { proxy: true, resolveProxyCompat: proxyCompatOption || { independent: "proxy-compat" } }],
- ],
- });
-
- return {
- name: "lwc-compat",
-
- transform(src: string) {
- const { code, map } = babel.transform(src, config);
- return { code, map };
- }
- };
-}
diff --git a/packages/lwc-compiler/src/rollup-plugins/minify.ts b/packages/lwc-compiler/src/rollup-plugins/minify.js
old mode 100755
new mode 100644
similarity index 52%
rename from packages/lwc-compiler/src/rollup-plugins/minify.ts
rename to packages/lwc-compiler/src/rollup-plugins/minify.js
index 53fb1817dc..b13419a695
--- a/packages/lwc-compiler/src/rollup-plugins/minify.ts
+++ b/packages/lwc-compiler/src/rollup-plugins/minify.js
@@ -1,21 +1,21 @@
-import * as babel from '@babel/core';
+import { transform } from '@babel/core';
import * as minify from 'babel-preset-minify';
import { BABEL_CONFIG_BASE } from '../babel-plugins';
-export const MINIFY_CONFIG: any = Object.assign({}, BABEL_CONFIG_BASE, {
+export const MINIFY_CONFIG = Object.assign({}, BABEL_CONFIG_BASE, {
presets: [[minify, { guards: false, evaluate: false }]]
});
/**
* Rollup plugin applying minification to the generated bundle.
*/
-export default function() {
+export default function(options) {
return {
- name: 'lwc-minify',
+ name: 'minify',
- transformBundle(src: string) {
- const { code, map } = babel.transform(src, MINIFY_CONFIG);
+ transformBundle(src) {
+ const { code, map } = transform(src, MINIFY_CONFIG);
return { code, map };
},
};
diff --git a/packages/lwc-compiler/src/rollup-plugins/module-resolver.js b/packages/lwc-compiler/src/rollup-plugins/module-resolver.js
new file mode 100644
index 0000000000..5be84e026e
--- /dev/null
+++ b/packages/lwc-compiler/src/rollup-plugins/module-resolver.js
@@ -0,0 +1,62 @@
+import * as path from 'path';
+
+const EMPTY_CSS_CONTENT = ``;
+
+function isRelativeImport(id) {
+ return id.startsWith('.');
+}
+
+function shouldRecordDependency(id) {
+ return !id.startsWith('babel-compat/') && !id.startsWith('proxy-compat/');
+}
+
+function isTemplateCss(id, importee) {
+ return path.extname(id) === '.css'
+ && path.extname(importee) === '.html'
+ && path.basename(id, '.css') === path.basename(importee, '.html');
+}
+
+/**
+ * Resolve files in the context of LWC modules and store external
+ * dependencies
+ */
+export default function({ moduleResolver, $metadata }) {
+ $metadata.rollupDependencies = [];
+
+ return {
+ name: 'module-resolver',
+
+ resolveId: function(id, importee) {
+ if (!isRelativeImport(id) && importee) {
+ if (shouldRecordDependency(id)) {
+ $metadata.rollupDependencies.push(id);
+ }
+ } else {
+ const relPath = importee ? path.dirname(importee) : '';
+ let absPath = path.join(relPath, id);
+
+ if (!path.extname(id)) {
+ absPath += '.js';
+ }
+
+ return moduleResolver.fileExists(absPath).then(exists => {
+ if (!exists && !isTemplateCss(id, importee)) {
+ throw new Error(
+ `Could not resolve '${id}' from '${importee}'`
+ );
+ }
+
+ return absPath;
+ });
+ }
+ },
+
+ load(id) {
+ return moduleResolver.fileExists(id).then(exists => {
+ return !exists && path.extname(id) === '.css'
+ ? EMPTY_CSS_CONTENT
+ : moduleResolver.readFile(id);
+ })
+ },
+ };
+}
diff --git a/packages/lwc-compiler/src/rollup-plugins/module-resolver.ts b/packages/lwc-compiler/src/rollup-plugins/module-resolver.ts
deleted file mode 100755
index f1c64d257f..0000000000
--- a/packages/lwc-compiler/src/rollup-plugins/module-resolver.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import * as path from "path";
-import { MetadataCollector } from "../bundler/meta-collector";
-import { NormalizedCompilerOptions } from "../compiler/options";
-
-const EMPTY_CSS_CONTENT = ``;
-
-function isRelativeImport(id: string) {
- return id.startsWith(".");
-}
-
-function isTemplateCss(id: string, importee: string) {
- return (
- path.extname(id) === ".css" &&
- path.extname(importee) === ".html" &&
- path.basename(id, ".css") === path.basename(importee, ".html")
- );
-}
-
-function fileExists(
- fileName: string,
- { files }: NormalizedCompilerOptions
-): boolean {
- return files.hasOwnProperty(fileName);
-}
-
-function readFile(
- fileName: string,
- options: NormalizedCompilerOptions
-): string {
- const { files } = options;
-
- if (fileExists(fileName, options)) {
- return files[fileName];
- } else {
- throw new Error(`No such file ${fileName}`);
- }
-}
-
-export default function({
- metadataCollector,
- options
-}: {
- metadataCollector: MetadataCollector;
- options: NormalizedCompilerOptions;
-}) {
- return {
- name: "lwc-module-resolver",
-
- resolveId(id: string, importee: string) {
- if (!isRelativeImport(id) && importee) {
- return;
- }
-
- const relPath = importee ? path.dirname(importee) : "";
- let absPath = path.join(relPath, id);
-
- if (!path.extname(id)) {
- absPath += ".js";
- }
-
- if (
- !fileExists(absPath, options) &&
- !isTemplateCss(id, importee)
- ) {
- throw new Error(
- `Could not resolve '${id}' from '${importee}'`
- );
- }
- return absPath;
- },
-
- load(id: string) {
- return !fileExists(id, options) && path.extname(id) === ".css"
- ? EMPTY_CSS_CONTENT
- : readFile(id, options);
- }
- };
-}
diff --git a/packages/lwc-compiler/src/rollup-plugins/transform.js b/packages/lwc-compiler/src/rollup-plugins/transform.js
new file mode 100644
index 0000000000..1f5a98f0af
--- /dev/null
+++ b/packages/lwc-compiler/src/rollup-plugins/transform.js
@@ -0,0 +1,50 @@
+import * as path from 'path';
+
+import styleTransform from '../transformers/style';
+import templateTransformer from '../transformers/template';
+import javascriptTransformer from '../transformers/javascript';
+
+/**
+ * Returns the associted transformer for a specific file
+ * @param {string} fileName
+ */
+function getTransformer(fileName) {
+ switch (path.extname(fileName)) {
+ case '.html':
+ return templateTransformer;
+
+ case '.css':
+ return styleTransform;
+
+ case '.js':
+ case '.ts':
+ return javascriptTransformer;
+
+ default:
+ throw new Error(`No available transformer for ${fileName}`);
+ }
+}
+
+/**
+ * Transfrom each file individually
+ */
+export default function(options) {
+ const { $metadata } = options;
+
+ return {
+ name: 'transform',
+
+ async transform(src, id) {
+ const transfom = getTransformer(id);
+ const result = await transfom(
+ src,
+ Object.assign({}, options, {
+ filename: id,
+ })
+ );
+
+ $metadata[id] = result.metadata;
+ return result;
+ },
+ };
+}
diff --git a/packages/lwc-compiler/src/rollup-plugins/transform.ts b/packages/lwc-compiler/src/rollup-plugins/transform.ts
deleted file mode 100755
index 39a05ad20e..0000000000
--- a/packages/lwc-compiler/src/rollup-plugins/transform.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { getTransformer, FileTransformerResult } from '../transformers/transformer';
-
-import { NormalizedCompilerOptions } from "../compiler/options";
-import { MetadataCollector } from '../bundler/meta-collector';
-
-export default function({
- options,
- metadataCollector,
-}: {
- options: NormalizedCompilerOptions;
- metadataCollector?: MetadataCollector
-}) {
- return {
- name: "lwc-file-transform",
- async transform(src: string, id: string): Promise {
- const transform = getTransformer(id);
- return await transform(
- src,
- id,
- options,
- metadataCollector,
- );
- }
- };
-}
diff --git a/packages/lwc-compiler/src/transform.js b/packages/lwc-compiler/src/transform.js
new file mode 100644
index 0000000000..4de0c462ed
--- /dev/null
+++ b/packages/lwc-compiler/src/transform.js
@@ -0,0 +1,45 @@
+import * as path from 'path';
+
+import styleTransform from './transformers/style';
+import templateTransformer from './transformers/template';
+import javascriptTransformer from './transformers/javascript';
+import compatPluginFactory from "./rollup-plugins/compat";
+import { isCompat } from './modes';
+
+/**
+ * Returns the associted transformer for a specific file
+ * @param {string} fileName
+ */
+function getTransformer(fileName) {
+ switch (path.extname(fileName)) {
+ case '.html':
+ return templateTransformer;
+
+ case '.css':
+ return styleTransform;
+
+ case '.js':
+ case '.ts':
+ return javascriptTransformer;
+
+ default:
+ throw new Error(`No available transformer for ${fileName}`);
+
+ }
+}
+
+/**
+ * Run approriate transformation for the passed source
+ */
+export default async function transform(src, id, options) {
+ const transfomer = getTransformer(id);
+ const mergedOptions = Object.assign({}, options, { filename: id });
+ const result = await Promise.resolve(transfomer( src, mergedOptions));
+
+ if (isCompat(options.mode)) {
+ const { transform } = compatPluginFactory(mergedOptions);
+ return transform(result.code);
+ }
+
+ return result;
+}
diff --git a/packages/lwc-compiler/src/transformers/__tests__/transform.spec.ts b/packages/lwc-compiler/src/transformers/__tests__/transform.spec.ts
deleted file mode 100755
index 2326e9674c..0000000000
--- a/packages/lwc-compiler/src/transformers/__tests__/transform.spec.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-import { transform } from "../../transformers/transformer";
-import { pretify } from "../../__tests__/utils";
-
-const VALID_TEST_JS = `
-import label from '@label/mylabel';
-function isTrue() {
- return label;
-}
-isTrue();
-`.trim();
-
-describe("transform", () => {
- it("should validate presence of src", () => {
- expect(() => transform()).toThrow(
- /Expect a string for source. Received undefined/
- );
- });
-
- it("should validate presence of id", () => {
- expect(() => transform(`console.log('Hello')`)).toThrow(
- /Expect a string for id. Received undefined/
- );
- });
-
- it("should throw if invalid resolveProxyCompat value is specified in compat mode", async () => {
- expect.assertions(1);
- try {
- const result = await transform(`debugger`, "foo.js", {
- namespace: "x",
- name: "foo",
- outputConfig: {
- compat: true,
- resolveProxyCompat: {
- badkey: "hello"
- }
- }
- });
- } catch (error) {
- expect(error.message).toBe(
- 'Unexpected resolveProxyCompat option, expected property "module", "global" or "independent"'
- );
- }
- });
-
- it("should throw when invalid javascript file is specified", async () => {
- expect.assertions(1);
- try {
- await transform(`const`, "foo.js", {
- namespace: "x",
- name: "foo"
- });
- } catch (error) {
- // TODO: Figure out how to disable error message code snippet for failing token.
- expect(
- error.message.indexOf("foo.js: Unexpected token (1:5)")
- ).toBe(0);
- }
- });
- it("should apply transformation for valid javascript file", async () => {
- const actual = `
- import { Element } from 'engine';
- export default class Foo extends Element {}
- `;
-
- const expected = `
- import _tmpl from "./foo.html";
- import { Element } from 'engine';
- export default class Foo extends Element {
- render() {
- return _tmpl;
- }
- }
- Foo.style = _tmpl.style;
- `;
-
- const { code } = await transform(actual, "foo.js", {
- namespace: "x",
- name: "foo"
- });
- expect(pretify(code)).toBe(pretify(expected));
- });
-
- it("should throw when invalid template file is specified", async () => {
- expect.assertions(1);
- try {
- await transform(` {
- const actual = `
-
- Hello
-
- `;
-
- const expected = `
- import style from './foo.css'
-
- export default function tmpl($api, $cmp, $slotset, $ctx) {
- const {
- t: api_text,
- h: api_element
- } = $api;
-
- return [api_element("div", {
- key: 1
- }, [api_text("Hello")])];
- }
-
- if (style) {
- const tagName = 'x-foo';
- const token = 'x-foo_foo';
- tmpl.token = token;
- tmpl.style = style(tagName, token);
- }
- `;
-
- const { code } = await transform(actual, "foo.html", {
- namespace: "x",
- name: "foo"
- });
-
- expect(pretify(code)).toBe(pretify(expected));
- });
-
- it("should throw when invalid tempalte file is specified", async () => {
- expect.assertions(1);
- try {
- await transform(`<`, "foo.css", {
- namespace: "x",
- name: "foo"
- });
- } catch (error) {
- expect(error.message).toBe(":1:1: Unknown word");
- }
- });
-
- it("should apply transformation for stylesheet file", async () => {
- const actual = `
- div {
- background-color: red;
- }
- `;
-
- const expected = `
- function style(tagName, token) {
- return \`
- div[\${token}] {
- background-color: red;
- }
- \`;
- }
- export default style;
- `;
-
- const { code } = await transform(actual, "foo.css", {
- namespace: "x",
- name: "foo"
- });
-
- expect(pretify(code)).toBe(pretify(expected));
- });
-
- it("javascript metadata", async () => {
- const content = `
- import { Element, api } from 'engine';
- /** Foo doc */
- export default class Foo extends Element {
- _privateTodo;
- @api get todo () {
- return this._privateTodo;
- }
- @api set todo (val) {
- return this._privateTodo = val;
- }
- @api
- index;
- }
- `;
-
- const result = await transform(content, "foo.js", {
- namespace: "x",
- name: "foo"
- });
-
- const metadata = result.metadata;
-
- expect(metadata.decorators).toEqual([
- {
- type: "api",
- targets: [
- { type: "property", name: "todo" },
- { type: "property", name: "index" }
- ]
- }
- ]);
- expect(metadata.doc).toBe("Foo doc");
- expect(metadata.declarationLoc).toEqual({
- start: { line: 4, column: 12 },
- end: { line: 14, column: 13 }
- });
- });
-});
diff --git a/packages/lwc-compiler/src/transformers/javascript.js b/packages/lwc-compiler/src/transformers/javascript.js
new file mode 100644
index 0000000000..37aba9224a
--- /dev/null
+++ b/packages/lwc-compiler/src/transformers/javascript.js
@@ -0,0 +1,24 @@
+import { transform } from '@babel/core';
+import * as lwcClassTransformPlugin from 'babel-plugin-transform-lwc-class';
+
+import { BABEL_CONFIG_BASE, BABEL_PLUGINS_BASE } from '../babel-plugins';
+
+export default function(code, options) {
+ const { filename } = options;
+
+ const config = Object.assign({}, BABEL_CONFIG_BASE, {
+ plugins: [
+ lwcClassTransformPlugin,
+ ...BABEL_PLUGINS_BASE,
+ ],
+ filename,
+ });
+
+ const transformed = transform(code, config);
+
+ return {
+ code: transformed.code,
+ map: transformed.map,
+ metadata: transformed.metadata,
+ };
+}
diff --git a/packages/lwc-compiler/src/transformers/javascript.ts b/packages/lwc-compiler/src/transformers/javascript.ts
deleted file mode 100755
index 3509f3fd77..0000000000
--- a/packages/lwc-compiler/src/transformers/javascript.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as babel from "@babel/core";
-import * as lwcClassTransformPlugin from "babel-plugin-transform-lwc-class";
-
-import { BABEL_CONFIG_BASE, BABEL_PLUGINS_BASE } from "../babel-plugins";
-import { NormalizedCompilerOptions } from "../compiler/options";
-import { FileTransformerResult } from "./transformer";
-import { MetadataCollector } from "../bundler/meta-collector";
-
-export default function(
- code: string,
- filename: string,
- options: NormalizedCompilerOptions,
- metadataCollector?: MetadataCollector
-): FileTransformerResult {
- const config = Object.assign({}, BABEL_CONFIG_BASE, {
- plugins: [lwcClassTransformPlugin, ...BABEL_PLUGINS_BASE],
- filename,
- });
- const result = babel.transform(code, config);
-
- const metadata: lwcClassTransformPlugin.Metadata = (result as any)
- .metadata;
-
- if (metadataCollector) {
- metadata.decorators.forEach(d => metadataCollector.collectDecorator(d));
- }
-
- return {
- code: result.code,
- map: null,
- metadata,
- };
-}
diff --git a/packages/lwc-compiler/src/transformers/style.js b/packages/lwc-compiler/src/transformers/style.js
new file mode 100644
index 0000000000..33a77a1526
--- /dev/null
+++ b/packages/lwc-compiler/src/transformers/style.js
@@ -0,0 +1,72 @@
+import * as postcss from 'postcss';
+import * as cssnano from 'cssnano';
+import postcssPluginRaptor from 'postcss-plugin-lwc';
+
+import { isProd } from '../modes';
+
+const TOKEN_PLACEHOLDER = '__TOKEN__';
+const TAG_NAME_PLACEHOLDER = '__TAG_NAME__';
+
+const EMPTY_CSS_OUTPUT = `
+const style = undefined;
+export default style;
+`
+
+function generateScopedStyle(src) {
+ src = src
+ .replace(new RegExp(TOKEN_PLACEHOLDER, 'g'), '${token}')
+ .replace(new RegExp(TAG_NAME_PLACEHOLDER, 'g'), '${tagName}');
+
+ return [
+ 'function style(tagName, token) {',
+ ' return `' + src + '`;',
+ '}',
+ 'export default style;'
+ ].join('\n');
+}
+
+/**
+ * Transforms a css string into a module exporting a function producing a stylesheet.
+ * The produced function accepts 2 parameters, tagName and token to enforce style scoping.
+ *
+ * export default function style({ token, style }) {
+ * return `div[${token}] { background-color: red; }`;
+ * }
+ *
+ * In the case where the stylesheet the produced module exports undefined.
+ *
+ * export default undefined;
+ */
+export default function transformStyle(src, options) {
+ const { mode } = options;
+
+ const plugins = [
+ postcssPluginRaptor({
+ token: TOKEN_PLACEHOLDER,
+ tagName: TAG_NAME_PLACEHOLDER,
+ }),
+ ];
+
+ if (isProd(mode)) {
+ plugins.push(
+ cssnano({
+ svgo: false,
+ preset: ['default'],
+ }),
+ );
+ }
+
+ return postcss(plugins)
+ .process(src, { from: undefined })
+ .then(res => {
+ const code =
+ res.css && res.css.length
+ ? generateScopedStyle(res.css)
+ : EMPTY_CSS_OUTPUT;
+
+ return {
+ code,
+ metadata: {},
+ };
+ });
+}
diff --git a/packages/lwc-compiler/src/transformers/style.ts b/packages/lwc-compiler/src/transformers/style.ts
deleted file mode 100755
index 33685a697b..0000000000
--- a/packages/lwc-compiler/src/transformers/style.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import * as postcss from "postcss";
-import * as cssnano from "cssnano";
-import postcssPluginRaptor from "postcss-plugin-lwc";
-
-import { NormalizedCompilerOptions } from "../compiler/options";
-import { FileTransformerResult } from "./transformer";
-
-const TOKEN_PLACEHOLDER = "__TOKEN__";
-const TAG_NAME_PLACEHOLDER = "__TAG_NAME__";
-
-const EMPTY_CSS_OUTPUT = `
-const style = undefined;
-export default style;
-`;
-
-function generateScopedStyle(src: string) {
- src = src
- .replace(new RegExp(TOKEN_PLACEHOLDER, "g"), "${token}")
- .replace(new RegExp(TAG_NAME_PLACEHOLDER, "g"), "${tagName}");
-
- return [
- "function style(tagName, token) {",
- " return `" + src + "`;",
- "}",
- "export default style;"
- ].join("\n");
-}
-
-/**
- * Transforms a css string into a module exporting a function producing a stylesheet.
- * The produced function accepts 2 parameters, tagName and token to enforce style scoping.
- *
- * export default function style({ token, style }) {
- * return `div[${token}] { background-color: red; }`;
- * }
- *
- * In the case where the stylesheet the produced module exports undefined.
- *
- * export default undefined;
- */
-export default function transformStyle(
- src: string,
- filename: string,
- { outputConfig }: NormalizedCompilerOptions
-): Promise {
- const plugins = [
- postcssPluginRaptor({
- token: TOKEN_PLACEHOLDER,
- tagName: TAG_NAME_PLACEHOLDER
- })
- ];
-
- if (outputConfig && outputConfig.minify) {
- plugins.push(
- cssnano({
- svgo: false,
- preset: ["default"]
- })
- );
- }
-
- return postcss(plugins)
- .process(src, { from: undefined })
- .then(res => {
- const code =
- res.css && res.css.length
- ? generateScopedStyle(res.css)
- : EMPTY_CSS_OUTPUT;
-
- return { code, map: null };
- });
-}
diff --git a/packages/lwc-compiler/src/transformers/template.js b/packages/lwc-compiler/src/transformers/template.js
new file mode 100644
index 0000000000..285d55032e
--- /dev/null
+++ b/packages/lwc-compiler/src/transformers/template.js
@@ -0,0 +1,42 @@
+import * as path from 'path';
+import compile from 'lwc-template-compiler';
+
+export function getTemplateToken(filename, options) {
+ const templateId = path.basename(filename, path.extname(filename));
+ return `${options.moduleNamespace}-${options.moduleName}_${templateId}`;
+}
+
+/**
+ * Transforms a HTML template into module exporting a template function.
+ * The transform also add a style import for the default stylesheet associated with
+ * the template regardless if there is an actual style or not.
+ */
+export default function(src, options) {
+ const { filename, moduleName, moduleNamespace } = options;
+ const { code: template, metadata, warnings } = compile(src, {});
+
+ const fatalError = warnings.find(warning => warning.level === 'error');
+ if (fatalError) {
+ throw new Error(fatalError.message);
+ }
+
+
+ const token = getTemplateToken(filename, options);
+ const cssName = path.basename(filename, path.extname(filename)) + '.css';
+
+ const code = [
+ `import style from './${cssName}'`,
+ '',
+ template,
+ '',
+ `if (style) {`,
+ ` const tagName = '${moduleNamespace}-${moduleName}';`,
+ ` const token = '${token}';`,
+ ``,
+ ` tmpl.token = token;`,
+ ` tmpl.style = style(tagName, token);`,
+ `}`,
+ ].join('\n');
+
+ return { code, metadata };
+}
diff --git a/packages/lwc-compiler/src/transformers/template.ts b/packages/lwc-compiler/src/transformers/template.ts
deleted file mode 100755
index dfad30ff07..0000000000
--- a/packages/lwc-compiler/src/transformers/template.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import * as path from "path";
-import compile from "lwc-template-compiler";
-import { NormalizedCompilerOptions } from "../compiler/options";
-import { FileTransformer } from "./transformer";
-
-// TODO: once we come up with a strategy to export all types from the module,
-// below interface should be removed and resolved from template-compiler module.
-export interface TemplateMetadata {
- templateUsedIds: string[];
- definedSlots: string[];
- templateDependencies: string[];
-}
-
-export function getTemplateToken(name: string, namespace: string) {
- const templateId = path.basename(name, path.extname(name));
- return `${namespace}-${name}_${templateId}`;
-}
-
-/**
- * Transforms a HTML template into module exporting a template function.
- * The transform also add a style import for the default stylesheet associated with
- * the template regardless if there is an actual style or not.
- */
-const transform: FileTransformer = function(
- src: string,
- filename: string,
- options: NormalizedCompilerOptions,
-) {
- const { name, namespace } = options;
- const { code: template, warnings } = compile(src, {});
-
- const fatalError = warnings.find(warning => warning.level === "error");
- if (fatalError) {
- throw new Error(fatalError.message);
- }
-
- const token = getTemplateToken(name, namespace);
- const cssName = path.basename(name, path.extname(name)) + ".css";
-
- const code = [
- `import style from './${cssName}'`,
- "",
- template,
- "",
- `if (style) {`,
- ` const tagName = '${namespace}-${name}';`,
- ` const token = '${token}';`,
- ``,
- ` tmpl.token = token;`,
- ` tmpl.style = style(tagName, token);`,
- `}`
- ].join("\n");
-
- return { code, map: null };
-};
-
-export default transform;
diff --git a/packages/lwc-compiler/src/transformers/transformer.ts b/packages/lwc-compiler/src/transformers/transformer.ts
deleted file mode 100755
index c1ce338a9d..0000000000
--- a/packages/lwc-compiler/src/transformers/transformer.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import * as path from "path";
-import * as lwcClassTransformPlugin from "babel-plugin-transform-lwc-class";
-
-import {
- NormalizedCompilerOptions,
- CompilerOptions,
- normalizeOptions
-} from "../compiler/options";
-
-import styleTransform from "./style";
-import templateTransformer, { TemplateMetadata } from "./template";
-import javascriptTransformer from "./javascript";
-import compatPluginFactory from "../rollup-plugins/compat";
-
-import { isString, isUndefined } from "../utils";
-import { MetadataCollector } from "../bundler/meta-collector";
-
-// TODO: Improve on metadata type by providing consistent interface. Currently
-// javascript transformer output differs from css and html in that later return a promise
-export interface FileTransformerResult {
- code: string;
- metadata?:
- | TemplateMetadata
- | lwcClassTransformPlugin.Metadata;
- map: null;
-}
-
-export type FileTransformer = (
- source: string,
- filename: string,
- options: NormalizedCompilerOptions,
- metadataCollector?: MetadataCollector
-) => FileTransformerResult | Promise;
-
-export function transform(src: string, id: string, options: CompilerOptions) {
- if (!isString(src)) {
- throw new Error(`Expect a string for source. Received ${src}`);
- }
-
- if (!isString(id)) {
- throw new Error(`Expect a string for id. Received ${id}`);
- }
-
- return transformFile(src, id, normalizeOptions(options));
-}
-
-export function getTransformer(fileName: string): FileTransformer {
- switch (path.extname(fileName)) {
- case ".html":
- return templateTransformer;
-
- case ".css":
- return styleTransform;
-
- case ".js":
- return javascriptTransformer;
-
- default:
- throw new TypeError(`No available transformer for "${fileName}"`);
- }
-}
-
-export async function transformFile(
- src: string,
- id: string,
- options: NormalizedCompilerOptions,
- metadataCollector?: MetadataCollector
-): Promise {
- const transformer = getTransformer(id);
- const result = await transformer(src, id, options, metadataCollector);
-
- if (options.outputConfig.compat) {
- const compatPlugin = compatPluginFactory(
- options.outputConfig.resolveProxyCompat
- );
- const compatResult = compatPlugin.transform(result.code);
- if (isUndefined(compatResult) || isUndefined(compatResult.code)) {
- throw new Error(
- "babel transform failed to produce code in compat mode"
- );
- }
- return { code: compatResult.code, map: null };
- }
-
- return result;
-}
diff --git a/packages/lwc-compiler/src/typings/@babel-core.d.ts b/packages/lwc-compiler/src/typings/@babel-core.d.ts
deleted file mode 100644
index 0d72592cc5..0000000000
--- a/packages/lwc-compiler/src/typings/@babel-core.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module '@babel/core' {
- const core: any;
- export = core;
-}
diff --git a/packages/lwc-compiler/src/typings/@babel-plugin-proposal-class-properties.d.ts b/packages/lwc-compiler/src/typings/@babel-plugin-proposal-class-properties.d.ts
deleted file mode 100755
index 54efcfce5e..0000000000
--- a/packages/lwc-compiler/src/typings/@babel-plugin-proposal-class-properties.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module '@babel/plugin-proposal-class-properties' {
- const props: any;
- export = props;
-}
diff --git a/packages/lwc-compiler/src/typings/@babel-plugin-proposal-object-rest-spread.d.ts b/packages/lwc-compiler/src/typings/@babel-plugin-proposal-object-rest-spread.d.ts
deleted file mode 100755
index e719245e67..0000000000
--- a/packages/lwc-compiler/src/typings/@babel-plugin-proposal-object-rest-spread.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module '@babel/plugin-proposal-object-rest-spread' {
- const spread: any;
- export = spread;
-}
diff --git a/packages/lwc-compiler/src/typings/babel-merge-copy.d.ts b/packages/lwc-compiler/src/typings/babel-merge-copy.d.ts
deleted file mode 100755
index f05d1677cb..0000000000
--- a/packages/lwc-compiler/src/typings/babel-merge-copy.d.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-declare module 'babel-plugin-check-es2015-constants' {
- const transform: any;
- export = transform;
-}
-
-declare module 'babel-plugin-transform-es2015-arrow-functions' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-block-scoped-functions' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-block-scoping' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-classes' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-computed-properties' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-destructuring' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-duplicate-keys' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-for-of' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-literals' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-object-super' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-parameters' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-shorthand-properties' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-spread' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-sticky-regex' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-template-literals' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-typeof-symbol' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-es2015-unicode-regex' {
- const transform: any;
- export = transform;
-}
-
-declare module 'babel-plugin-transform-async-to-generator' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-regenerator' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-runtime' {
- const transform: any;
- export = transform;
-}
-
-declare module 'babel-plugin-syntax-trailing-function-commas' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-exponentiation-operator' {
- const transform: any;
- export = transform;
-}
-
-declare module 'babel-plugin-transform-object-rest-spread' {
- const transform: any;
- export = transform;
-}
-declare module 'babel-plugin-transform-class-properties' {
- const transform: any;
- export = transform;
-}
-
-declare module 'babel-preset-minify' {
- const transform: any;
- export = transform;
-}
-
-declare module 'babel-plugin-transform-proxy-compat' {
- const transform: any;
- export = transform;
-}
diff --git a/packages/lwc-compiler/src/typings/babel-plugins.d.ts b/packages/lwc-compiler/src/typings/babel-plugins.d.ts
deleted file mode 100755
index 74725e223c..0000000000
--- a/packages/lwc-compiler/src/typings/babel-plugins.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module 'babel-plugins' {
- const plugins: any;
- export = plugins;
-}
diff --git a/packages/lwc-compiler/src/typings/babel-preset-compat.d.ts b/packages/lwc-compiler/src/typings/babel-preset-compat.d.ts
deleted file mode 100755
index 59b7a017c3..0000000000
--- a/packages/lwc-compiler/src/typings/babel-preset-compat.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module 'babel-preset-compat' {
- const compat: any;
- export = compat;
-}
diff --git a/packages/lwc-compiler/src/typings/cssnano.d.ts b/packages/lwc-compiler/src/typings/cssnano.d.ts
deleted file mode 100755
index 4353eba786..0000000000
--- a/packages/lwc-compiler/src/typings/cssnano.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module 'cssnano' {
- const nano: any;
- export = nano;
-}
diff --git a/packages/lwc-compiler/src/typings/rollup-plugin-replace.d.ts b/packages/lwc-compiler/src/typings/rollup-plugin-replace.d.ts
deleted file mode 100755
index 3a8a237cb0..0000000000
--- a/packages/lwc-compiler/src/typings/rollup-plugin-replace.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module 'rollup-plugin-replace' {
- const replace: any;
- export = replace;
-}
diff --git a/packages/lwc-compiler/src/typings/rollup.d.ts b/packages/lwc-compiler/src/typings/rollup.d.ts
deleted file mode 100755
index b794ab5132..0000000000
--- a/packages/lwc-compiler/src/typings/rollup.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-declare module 'rollup' {
- export const rollup: any;
-}
diff --git a/packages/lwc-compiler/src/utils.js b/packages/lwc-compiler/src/utils.js
new file mode 100644
index 0000000000..10eaf2d812
--- /dev/null
+++ b/packages/lwc-compiler/src/utils.js
@@ -0,0 +1,27 @@
+/**
+ * Takes 2 arrays and returns an object formed by associating properties with values
+ * @param {string[]} props
+ * @param {any[]} values
+ */
+export function zipObject(props, values) {
+ return props.reduce((obj, prop, index) => {
+ obj[prop] = values[index];
+ return obj;
+ }, {});
+}
+
+/**
+ * Returns true if the value is undefined
+ * @param {any} o
+ */
+export function isUndefined(o) {
+ return o === undefined;
+}
+
+/**
+ * Returns true if the value is a string
+ * @param {any} o
+ */
+export function isString(o) {
+ return typeof o === 'string';
+}
diff --git a/packages/lwc-compiler/src/utils.ts b/packages/lwc-compiler/src/utils.ts
deleted file mode 100755
index 2fe2aec76b..0000000000
--- a/packages/lwc-compiler/src/utils.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Returns true if the value is undefined
- * @param {any} o
- */
-export function isUndefined(o: any): o is undefined {
- return o === undefined;
-}
-
-/**
- * Returns true if the value is a string
- * @param {any} o
- */
-export function isString(o: any): o is string {
- return typeof o === 'string';
-}
-
-/**
- * Returns true if the value is a boolean
- * @param {any} o
- */
-export function isBoolean(o: any): o is boolean {
- return typeof o === 'boolean';
-}
diff --git a/packages/lwc-compiler/tsconfig.json b/packages/lwc-compiler/tsconfig.json
old mode 100755
new mode 100644
index 7d10d48545..86b07926b6
--- a/packages/lwc-compiler/tsconfig.json
+++ b/packages/lwc-compiler/tsconfig.json
@@ -1,29 +1,19 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
- "allowJs": false,
- "checkJs": false,
"target": "es2017",
"module": "commonjs",
- "noImplicitAny": true,
- "sourceMap": true,
- "declaration": true,
- "rootDir": "src",
"outDir": "dist/commonjs",
- "declarationDir": "dist/types",
- "moduleResolution": "node",
- "strict": true,
- "strictFunctionTypes": true,
- "strictPropertyInitialization": true,
- "suppressImplicitAnyIndexErrors": true,
- "noUnusedLocals": true,
+ "checkJs": false,
+ "allowJs": true,
+ "declaration": false
},
"include": [
- "src/**/*"
+ "src/**/*",
],
"exclude": [
"**/node_modules",
"**/dist",
- "**/__tests__"
+ "**/__tests__",
]
}
diff --git a/packages/lwc-compiler/webpack.config.js b/packages/lwc-compiler/webpack.config.js
old mode 100755
new mode 100644
diff --git a/packages/lwc-template-compiler/package.json b/packages/lwc-template-compiler/package.json
index faae4d4725..20ec5479cb 100644
--- a/packages/lwc-template-compiler/package.json
+++ b/packages/lwc-template-compiler/package.json
@@ -3,7 +3,7 @@
"version": "0.20.0",
"description": "Template compiler package",
"main": "dist/commonjs/index.js",
- "typings": "dist/types/",
+ "typings": "dist/types/index.d.ts",
"license": "MIT",
"scripts": {
"clean": "rm -rf dist",
diff --git a/packages/rollup-plugin-lwc-compiler/package.json b/packages/rollup-plugin-lwc-compiler/package.json
index ee2b031468..35f1d1ecb2 100644
--- a/packages/rollup-plugin-lwc-compiler/package.json
+++ b/packages/rollup-plugin-lwc-compiler/package.json
@@ -18,7 +18,7 @@
"rollup-pluginutils": "^2.0.1"
},
"peerDependencies": {
- "lwc-compiler": "0.19.x",
- "lwc-engine": "0.19.x"
+ "lwc-compiler": "0.18.x",
+ "lwc-engine": "0.18.x"
}
}
diff --git a/packages/rollup-plugin-lwc-compiler/src/index.js b/packages/rollup-plugin-lwc-compiler/src/index.js
index cec5e522dd..c1e1e52b31 100644
--- a/packages/rollup-plugin-lwc-compiler/src/index.js
+++ b/packages/rollup-plugin-lwc-compiler/src/index.js
@@ -1,26 +1,17 @@
-const fs = require("fs");
-const path = require("path");
-const babel = require("@babel/core");
-const minify = require("babel-preset-minify");
-const compiler = require("lwc-compiler");
-const pluginUtils = require("rollup-pluginutils");
-const replacePlugin = require("rollup-plugin-replace");
-const lwcResolver = require("lwc-module-resolver");
-const rollupCompatPlugin = require("rollup-plugin-compat").default;
+const fs = require('fs');
+const path = require('path');
+const compiler = require('lwc-compiler');
+const pluginUtils = require('rollup-pluginutils');
+const lwcResolver = require('lwc-module-resolver');
+const rollupCompatPlugin = require('rollup-plugin-compat').default;
-
-const { DEFAULT_NS, DEFAULT_OPTIONS, DEFAULT_MODE } = require("./constants");
+const { DEFAULT_NS, DEFAULT_OPTIONS, DEFAULT_MODE } = require('./constants');
function getModuleQualifiedName(file, { mapNamespaceFromPath }) {
- const registry = {
- entry: file,
- moduleSpecifier: null,
- moduleName: null,
- moduleNamespace: DEFAULT_NS
- };
+ const registry = { entry: file, moduleSpecifier: null, moduleName: null, moduleNamespace: DEFAULT_NS };
const fileName = path.basename(file, path.extname(file));
const rootParts = path.dirname(file).split(path.sep);
- const nameParts = fileName.split("-");
+ const nameParts = fileName.split('-');
const validModuleName = nameParts.length > 1;
if (mapNamespaceFromPath) {
@@ -28,7 +19,7 @@ function getModuleQualifiedName(file, { mapNamespaceFromPath }) {
registry.moduleNamespace = rootParts.pop();
} else if (validModuleName) {
registry.moduleNamespace = nameParts.shift();
- registry.moduleName = nameParts.join("-");
+ registry.moduleName = nameParts.join('-');
} else {
registry.moduleName = fileName;
}
@@ -37,7 +28,7 @@ function getModuleQualifiedName(file, { mapNamespaceFromPath }) {
}
function normalizeResult(result) {
- return { code: result.code || result, map: result.map || { mappings: "" } };
+ return { code: result.code || result, map: result.map || { mappings: '' } };
}
/*
@@ -53,14 +44,9 @@ function normalizeResult(result) {
module.exports = function rollupLwcCompiler(pluginOptions = {}) {
const { include, exclude, mapNamespaceFromPath } = pluginOptions;
const filter = pluginUtils.createFilter(include, exclude);
- const mergedPluginOptions = Object.assign(
- {},
- DEFAULT_OPTIONS,
- pluginOptions,
- {
- mapNamespaceFromPath: Boolean(mapNamespaceFromPath)
- }
- );
+ const mergedPluginOptions = Object.assign({}, DEFAULT_OPTIONS, pluginOptions, {
+ mapNamespaceFromPath: Boolean(mapNamespaceFromPath),
+ });
const { mode, compat } = mergedPluginOptions;
// We will compose compat plugin on top of this one
@@ -70,17 +56,13 @@ module.exports = function rollupLwcCompiler(pluginOptions = {}) {
const modulePaths = {};
return {
- name: "rollup-plugin-lwc-compiler",
+ name: 'rollup-plugin-lwc-compiler',
options(rollupOptions) {
const entry = rollupOptions.input || rollupOptions.entry;
const entryDir = mergedPluginOptions.rootDir || path.dirname(entry);
- const externalPaths = mergedPluginOptions.resolveFromPackages
- ? lwcResolver.resolveLwcNpmModules(mergedPluginOptions)
- : {};
- const sourcePaths = mergedPluginOptions.resolveFromSource
- ? lwcResolver.resolveModulesInDir(entryDir, mergedPluginOptions)
- : {};
+ const externalPaths = mergedPluginOptions.resolveFromPackages ? lwcResolver.resolveLwcNpmModules(mergedPluginOptions) : {};
+ const sourcePaths = mergedPluginOptions.resolveFromSource ? lwcResolver.resolveModulesInDir(entryDir, mergedPluginOptions): {};
Object.assign(modulePaths, externalPaths, sourcePaths);
},
@@ -91,11 +73,8 @@ module.exports = function rollupLwcCompiler(pluginOptions = {}) {
}
// Normalize relative import to absolute import
- if (importee.startsWith(".") && importer) {
- const normalizedPath = path.resolve(
- path.dirname(importer),
- importee
- );
+ if (importee.startsWith('.') && importer) {
+ const normalizedPath = path.resolve(path.dirname(importer), importee);
return pluginUtils.addExtension(normalizedPath);
}
@@ -105,10 +84,10 @@ module.exports = function rollupLwcCompiler(pluginOptions = {}) {
load(id) {
const exists = fs.existsSync(id);
- const isCSS = path.extname(id) === ".css";
+ const isCSS = path.extname(id) === '.css';
if (!exists && isCSS) {
- return "";
+ return '';
}
// Check if compat knows how to load this file
@@ -121,63 +100,36 @@ module.exports = function rollupLwcCompiler(pluginOptions = {}) {
}
// If we don't find the moduleId, just resolve the module name/namespace
- const moduleEntry = Object.values(modulePaths).find(
- r => id === r.entry
- );
- const moduleRegistry =
- moduleEntry || getModuleQualifiedName(id, mergedPluginOptions);
+ const moduleEntry = Object.values(modulePaths).find(r => id === r.entry);
+ const moduleRegistry = moduleEntry || getModuleQualifiedName(id, mergedPluginOptions);
let result = code;
if (!rollupCompatInstance.knownCompatModule(id)) {
result = await compiler.transform(code, id, {
mode: DEFAULT_MODE, // Use always default mode since any other (prod or compat) will be resolved later
- name: moduleRegistry.moduleName,
- namespace: moduleRegistry.moduleNamespace,
+ moduleName: moduleRegistry.moduleName,
+ moduleNamespace: moduleRegistry.moduleNamespace,
moduleSpecifier: moduleRegistry.moduleSpecifier
});
}
result = normalizeResult(result);
- if (mode === "compat" || mode === "prod_compat") {
- result = normalizeResult(
- rollupCompatInstance.transform(result.code, id)
- );
+ if (mode === 'compat' || mode === 'prod_compat') {
+ result = normalizeResult(rollupCompatInstance.transform(result.code, id));
}
return { code: result.code, map: result.map };
+
},
transformBundle(code) {
- if (mode === "compat" || mode === "prod_compat") {
+ if (mode === 'compat' || mode === 'prod_compat') {
code = rollupCompatInstance.transformBundle(code);
}
- let result = undefined;
- if (mode === "prod" || mode === "prod_compat") {
- const rollupReplace = replacePlugin({
- "process.env.NODE_ENV": JSON.stringify("production")
- });
- const resultReplace = rollupReplace.transform(
- code,
- "$__tmpBundleSrc"
- );
-
- const transformConfig = {
- babelrc: false,
- sourceMaps: true,
- parserOpts: { plugins: ["*"] },
- presets: [[minify, { guards: false, evaluate: false }]],
- };
-
- const output = babel.transform(
- resultReplace ? resultReplace.code : code,
- transformConfig
- );
-
- result = output.code;
- }
- return result || code;
+
+ return compiler.transformBundle(code, { mode });
}
};
};
diff --git a/yarn.lock b/yarn.lock
index 26aeffb28c..3a428bef82 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -502,30 +502,20 @@
dependencies:
"@types/estree" "*"
-"@types/babel-core@^6.25.3":
- version "6.25.3"
- resolved "https://registry.npmjs.org/@types/babel-core/-/babel-core-6.25.3.tgz#c7fda09007375ae89942307917ed21ed309a1c2a"
- dependencies:
- "@types/babel-generator" "*"
- "@types/babel-template" "*"
- "@types/babel-traverse" "*"
- "@types/babel-types" "*"
- "@types/babylon" "*"
-
-"@types/babel-generator@*", "@types/babel-generator@^6.25.1":
+"@types/babel-generator@^6.25.1":
version "6.25.1"
resolved "http://npm.lwcjs.org/@types/babel-generator/-/babel-generator-6.25.1/f86ab3cf132b04597fe6c431d3083aaf1b76b530.tgz#f86ab3cf132b04597fe6c431d3083aaf1b76b530"
dependencies:
"@types/babel-types" "*"
-"@types/babel-template@*", "@types/babel-template@^6.25.0":
+"@types/babel-template@^6.25.0":
version "6.25.0"
resolved "http://npm.lwcjs.org/@types/babel-template/-/babel-template-6.25.0/2505d7b55b88f821d98048b4fdf07b3b22563d30.tgz#2505d7b55b88f821d98048b4fdf07b3b22563d30"
dependencies:
"@types/babel-types" "*"
"@types/babylon" "*"
-"@types/babel-traverse@*", "@types/babel-traverse@^6.25.3":
+"@types/babel-traverse@^6.25.3":
version "6.25.3"
resolved "http://npm.lwcjs.org/@types/babel-traverse/-/babel-traverse-6.25.3/34dd69d1e469aee75e20ba00fbc52c7bc717b1c8.tgz#34dd69d1e469aee75e20ba00fbc52c7bc717b1c8"
dependencies:
@@ -541,21 +531,10 @@
dependencies:
"@types/babel-types" "*"
-"@types/chokidar@^1.7.5":
- version "1.7.5"
- resolved "https://registry.npmjs.org/@types/chokidar/-/chokidar-1.7.5.tgz#1fa78c8803e035bed6d98e6949e514b133b0c9b6"
- dependencies:
- "@types/events" "*"
- "@types/node" "*"
-
"@types/estree@*":
version "0.0.38"
resolved "http://npm.lwcjs.org/@types/estree/-/estree-0.0.38/c1be40aa933723c608820a99a373a16d215a1ca2.tgz#c1be40aa933723c608820a99a373a16d215a1ca2"
-"@types/events@*":
- version "1.2.0"
- resolved "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86"
-
"@types/he@^0.5.29":
version "0.5.29"
resolved "http://npm.lwcjs.org/@types/he/-/he-0.5.29/67f9392287b05558013d1cabc96801a5185adbea.tgz#67f9392287b05558013d1cabc96801a5185adbea"
@@ -7586,10 +7565,6 @@ rollup@~0.56.2:
version "0.56.2"
resolved "http://npm.lwcjs.org/rollup/-/rollup-0.56.2/1788cf56d4350b6d8ecf76b5d654c59c7bf9c24a.tgz#1788cf56d4350b6d8ecf76b5d654c59c7bf9c24a"
-rollup@~0.56.5:
- version "0.56.5"
- resolved "http://npm.lwcjs.org/rollup/-/rollup-0.56.5/40fe3cf0cd1659d469baad11f4d5b6336c14ce84.tgz#40fe3cf0cd1659d469baad11f4d5b6336c14ce84"
-
run-async@^2.2.0:
version "2.3.0"
resolved "http://npm.lwcjs.org/run-async/-/run-async-2.3.0/0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"