diff --git a/.travis.yml b/.travis.yml index 4f21a13d49..2d4a4a74d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,6 @@ cache: - ".meteor" - ".babel-cache" script: - - export TEST_PACKAGES_EXCLUDE="less" - export phantom=false # to skip Downloading Chromium on every run # https://github.com/dfernandez79/puppeteer/blob/main/README.md#q-chromium-gets-downloaded-on-every-npm-ci-run-how-can-i-cache-the-download diff --git a/History.md b/History.md index d121e2085b..062ba91a88 100644 --- a/History.md +++ b/History.md @@ -54,6 +54,7 @@ - Update `cordova-plugin-meteor-webapp` to v2 - Removed dependency on `cordova-plugin-whitelist` as it is now included in core - Cordova Meteor plugin is now using AndroidX + - Added new settings option `Meteor.settings.packages.webapp.alwaysReturnContent` that will always return content on requests like `POST`, essentially enabling behavior prior to Meteor 2.3.1. #### Independent Releases @@ -75,6 +76,16 @@ * `ecmascript-runtime-client@0.12.1` - Revert `core-js` to v3.15.2 due to issues in legacy build with arrays, [see issue for more details](https://github.com/meteor/meteor/issues/11662) +* `modern-browsers@0.1.7` + - Added `firefoxMobile` as an alias for `firefox` + +## v2.4.1, 2021-10-12 + +#### Meteor Version Release + +* `meteor-tool@2.4.1` + - Patch to make 2.4.1 compatible with Push to Deploy feature in Galaxy (Meteor Cloud) + ## v2.4, 2021-09-15 #### Highlights @@ -187,6 +198,13 @@ * `callback-hook@1.4.0` - Added `forEach` iterator to be more in-line with the ES use for iterations. `each` is now deprecated, but will remain supported. + +## v2.3.7, 2021-10-12 + +#### Meteor Version Release + +* `meteor-tool@2.3.7` + - Patch to make 2.3.7 compatible with Push to Deploy feature in Galaxy (Meteor Cloud) ## v2.3.6, 2021-09-02 @@ -541,6 +559,13 @@ * `react-fast-refresh@0.1.1` - Fixed the package to work in IE11 + +## v2.2.4, 2021-10-12 + +#### Meteor Version Release + +* `meteor-tool@2.2.4` + - Patch to make 2.2.4 compatible with Push to Deploy feature in Galaxy (Meteor Cloud) ## v2.2.3, 2021-08-12 @@ -643,6 +668,14 @@ * `webapp@1.10.1` - Fix for UNIX sockets with node cluster. [#11369](https://github.com/meteor/meteor/pull/11369) + +## v2.1.2, 2021-10-12 + +#### Meteor Version Release + +* `meteor-tool@2.1.2` + - Patch to make 2.1.2 compatible with Push to Deploy feature in Galaxy (Meteor Cloud) + ## v2.1.1, 2021-04-06 ### Changes @@ -687,6 +720,13 @@ * N/A +## v2.0.1, 2021-10-12 + +#### Meteor Version Release + +* `meteor-tool@2.0.1` + - Patch to make 2.0.1 compatible with Push to Deploy feature in Galaxy (Meteor Cloud) + ## v2.0, 2021-01-20 ### Changes @@ -753,6 +793,13 @@ Simple run `meteor update` in your app. Great new features and no breaking changes (except one package deprecation). You can always check our [Roadmap](./Roadmap.md) to understand what is next. +## v1.12.2, 2021-10-12 + +#### Meteor Version Release + +* `meteor-tool@1.12.2` + - Patch to make 1.12.2 compatible with Push to Deploy feature in Galaxy (Meteor Cloud) + ## v1.12.1, 2021-01-06 ### Breaking changes diff --git a/packages/ecmascript/README.md b/packages/ecmascript/README.md index e624886590..00048a5179 100644 --- a/packages/ecmascript/README.md +++ b/packages/ecmascript/README.md @@ -249,7 +249,7 @@ Here is a list of the Babel transformers that are currently enabled: The ECMAScript 2015 standard library has grown to include new APIs and data structures, some of which can be implemented ("polyfilled") using -JavaScript that runs in all engines and browsers today. Here are three new +JavaScript that runs in all engines and browsers today. Here are four new constructors that are guaranteed to be available when the `ecmascript` package is installed: diff --git a/packages/ecmascript/package.js b/packages/ecmascript/package.js index c93509cd8c..a9c7c5821d 100644 --- a/packages/ecmascript/package.js +++ b/packages/ecmascript/package.js @@ -40,4 +40,5 @@ Package.onTest(function(api) { api.addFiles('bare-test-file.js', ['client', 'server'], { bare: true, }); + api.addFiles('runtime-tests-client.js', ['client', 'web.browser.legacy']); }); diff --git a/packages/ecmascript/runtime-tests-client.js b/packages/ecmascript/runtime-tests-client.js new file mode 100644 index 0000000000..47834c0904 --- /dev/null +++ b/packages/ecmascript/runtime-tests-client.js @@ -0,0 +1,22 @@ +// Regression test for web.browser.legacy - see https://github.com/meteor/meteor/issues/11662 +Tinytest.add('ecmascript - runtime - NodeList spread', test => { + const div = document.createElement('div'); + document.body.appendChild(div); + + for (let i = 0; i < 5; i++) { + const child = document.createElement('div'); + child.innerText = `child ${i}`; + div.appendChild(child); + } + + try { + test.equal(div.childNodes?.length, 5); + const arr = [...div.childNodes]; + + arr.forEach((el, i) => { + test.equal(el.innerText, `child ${i}`); + }); + } finally { + document.body.removeChild(div); + } +}); diff --git a/packages/ecmascript/runtime-tests.js b/packages/ecmascript/runtime-tests.js index bea03b6ab6..f0cb308a97 100644 --- a/packages/ecmascript/runtime-tests.js +++ b/packages/ecmascript/runtime-tests.js @@ -1,28 +1,28 @@ -const isNode8OrLater = Meteor.isServer && - parseInt(process.versions.node) >= 8; +const isNode8OrLater = Meteor.isServer && parseInt(process.versions.node) >= 8; -Tinytest.add("ecmascript - runtime - template literals", (test) => { +Tinytest.add('ecmascript - runtime - template literals', test => { function dump(strings, ...expressions) { const copy = Object.create(null); Object.assign(copy, strings); copy.raw = strings.raw; return [copy, expressions]; - }; + } - const foo = "B"; + const foo = 'B'; - test.equal(`\u0041${foo}C`, "ABC"); + test.equal(`\u0041${foo}C`, 'ABC'); - test.equal(dump`\u0041${foo}C`, [{ - 0: "A", - 1: "C", - raw: ["\\u0041", "C"] - }, [ - "B" - ]]); + test.equal(dump`\u0041${foo}C`, [ + { + 0: 'A', + 1: 'C', + raw: ['\\u0041', 'C'], + }, + ['B'], + ]); }); -Tinytest.add("ecmascript - runtime - classes - basic", (test) => { +Tinytest.add('ecmascript - runtime - classes - basic', test => { { class Foo { constructor(x) { @@ -35,7 +35,7 @@ Tinytest.add("ecmascript - runtime - classes - basic", (test) => { // Foo(); // called without `new` // }); - test.equal((new Foo(3)).x, 3); + test.equal(new Foo(3).x, 3); } { @@ -51,9 +51,9 @@ Tinytest.add("ecmascript - runtime - classes - basic", (test) => { // Foo(); // called without `new` // }); - test.equal((new Foo(3)).x, 3); - test.isTrue((new Foo(3)) instanceof Foo); - test.isTrue((new Foo(3)) instanceof Bar); + test.equal(new Foo(3).x, 3); + test.isTrue(new Foo(3) instanceof Foo); + test.isTrue(new Foo(3) instanceof Bar); } { @@ -68,11 +68,11 @@ Tinytest.add("ecmascript - runtime - classes - basic", (test) => { } test.equal(Foo.staticMethod(), 'classy'); - test.equal((new Foo).prototypeMethod(), 'prototypical'); + test.equal(new Foo().prototypeMethod(), 'prototypical'); } }); -Tinytest.add("ecmascript - runtime - classes - use before declare", (test) => { +Tinytest.add('ecmascript - runtime - classes - use before declare', test => { const x = function asdf() {}; if (typeof asdf === 'function') { // We seem to be in IE 8, where function names leak into the enclosing @@ -88,9 +88,7 @@ Tinytest.add("ecmascript - runtime - classes - use before declare", (test) => { }); }); - -Tinytest.add("ecmascript - runtime - classes - inheritance", (test) => { - +Tinytest.add('ecmascript - runtime - classes - inheritance', test => { // uses `babelHelpers.inherits` { class Foo { @@ -98,7 +96,7 @@ Tinytest.add("ecmascript - runtime - classes - inheritance", (test) => { return 1; } } - Foo.static2 = function () { + Foo.static2 = function() { return 2; }; @@ -128,12 +126,14 @@ Tinytest.add("ecmascript - runtime - classes - inheritance", (test) => { } }); -Tinytest.add("ecmascript - runtime - classes - computed props", (test) => { +Tinytest.add('ecmascript - runtime - classes - computed props', test => { { - const frob = "inc"; + const frob = 'inc'; class Foo { - static [frob](n) { return n+1; } + static [frob](n) { + return n + 1; + } } test.equal(Foo.inc(3), 4); @@ -145,35 +145,39 @@ if (Meteor.isServer) { // in classes on browsers that support them in the first place, and on // the server. (Technically they just need a working // Object.defineProperty, found in IE9+ and all modern environments.) - Tinytest.add("ecmascript - runtime - classes - getters/setters", (test) => { + Tinytest.add('ecmascript - runtime - classes - getters/setters', test => { // uses `babelHelpers.createClass` class Foo { - get two() { return 1+1; } - static get three() { return 1+1+1; } + get two() { + return 1 + 1; + } + static get three() { + return 1 + 1 + 1; + } } - test.equal((new Foo).two, 2); + test.equal(new Foo().two, 2); test.equal(Foo.three, 3); }); } -export const testExport = "oyez"; +export const testExport = 'oyez'; -Tinytest.add("ecmascript - runtime - classes - properties", (test) => { +Tinytest.add('ecmascript - runtime - classes - properties', test => { class ClassWithProperties { - property = ["prop", "rty"].join("e"); + property = ['prop', 'rty'].join('e'); static staticProp = 1234; - check = (self) => { - import { testExport as oyez } from "./runtime-tests.js"; - test.equal(oyez, "oyez"); + check = self => { + import { testExport as oyez } from './runtime-tests.js'; + test.equal(oyez, 'oyez'); test.isTrue(self === this); - test.equal(this.property, "property"); + test.equal(this.property, 'property'); }; method() { - import { testExport as oyez } from "./runtime-tests.js"; - test.equal(oyez, "oyez"); + import { testExport as oyez } from './runtime-tests.js'; + test.equal(oyez, 'oyez'); } } @@ -189,16 +193,16 @@ Tinytest.add("ecmascript - runtime - classes - properties", (test) => { cwp.method(); }); -Tinytest.add("ecmascript - runtime - block scope", (test) => { +Tinytest.add('ecmascript - runtime - block scope', test => { { const buf = []; const thunks = []; function print(x) { buf.push(x); - }; + } function doLater(f) { thunks.push(f); - }; + } for (let i = 0; i < 3; i++) { print(i); @@ -217,11 +221,15 @@ Tinytest.add("ecmascript - runtime - block scope", (test) => { } }); -Tinytest.add("ecmascript - runtime - classes - super", (test) => { +Tinytest.add('ecmascript - runtime - classes - super', test => { { class Class1 { - foo() { return 123; } - static bar() { return 1; } + foo() { + return 123; + } + static bar() { + return 1; + } } class Class2 extends Class1 {} class Class3 extends Class2 { @@ -230,34 +238,41 @@ Tinytest.add("ecmascript - runtime - classes - super", (test) => { } } - test.equal((new Class3).foo(), 124); + test.equal(new Class3().foo(), 124); } { class Foo { - constructor(value) { this.value = value; } - x() { return this.value; } + constructor(value) { + this.value = value; + } + x() { + return this.value; + } } class Bar extends Foo { - constructor() { super(123); } - x() { return super.x(); } + constructor() { + super(123); + } + x() { + return super.x(); + } } - test.equal((new Bar).x(), 123); + test.equal(new Bar().x(), 123); } }); -Tinytest.add("ecmascript - runtime - object rest/spread", (test) => { - const middle = {b:2, c:3}; +Tinytest.add('ecmascript - runtime - object rest/spread', test => { + const middle = { b: 2, c: 3 }; // uses `babelHelpers._extends` - const full = {a:1, ...middle, d:4}; - test.equal(full, {a:1, b:2, c:3, d:4}); + const full = { a: 1, ...middle, d: 4 }; + test.equal(full, { a: 1, b: 2, c: 3, d: 4 }); }); -Tinytest.add("ecmascript - runtime - spread args to new", (test) => { - - const Foo = function (one, two, three) { +Tinytest.add('ecmascript - runtime - spread args to new', test => { + const Foo = function(one, two, three) { test.isTrue(this instanceof Foo); test.equal(one, 1); test.equal(two, 2); @@ -272,35 +287,38 @@ Tinytest.add("ecmascript - runtime - spread args to new", (test) => { test.isTrue(foo.created); }); -Tinytest.add("ecmascript - runtime - Map spread", (test) => { - const map = new Map; +Tinytest.add('ecmascript - runtime - Map spread', test => { + const map = new Map(); map.set(0, 1); map.set(1, 2); map.set(2, 3); - test.equal([...map], [ - [0, 1], - [1, 2], - [2, 3] - ]); + test.equal( + [...map], + [ + [0, 1], + [1, 2], + [2, 3], + ] + ); }); -Tinytest.add("ecmascript - runtime - Set spread", (test) => { - const set = new Set; +Tinytest.add('ecmascript - runtime - Set spread', test => { + const set = new Set(); - set.add("a"); + set.add('a'); set.add(1); set.add(false); - test.equal([...set], ["a", 1, false]); + test.equal([...set], ['a', 1, false]); }); -Tinytest.add("ecmascript - runtime - destructuring", (test) => { - const obj = {a:1, b:2}; - const {a, ...rest} = obj; +Tinytest.add('ecmascript - runtime - destructuring', test => { + const obj = { a: 1, b: 2 }; + const { a, ...rest } = obj; test.equal(a, 1); - test.equal(rest, {b:2}); + test.equal(rest, { b: 2 }); const {} = {}; @@ -308,33 +326,33 @@ Tinytest.add("ecmascript - runtime - destructuring", (test) => { const {} = null; }); - const [x, y, z] = function*() { + const [x, y, z] = (function*() { let n = 1; while (true) { yield n++; } - }(); + })(); test.equal(x, 1); test.equal(y, 2); test.equal(z, 3); }); -Tinytest.addAsync("ecmascript - runtime - misc support", (test, done) => { +Tinytest.addAsync('ecmascript - runtime - misc support', (test, done) => { // Verify that the runtime was installed. if (Meteor.isLegacy) { - test.equal(typeof meteorBabelHelpers, "object"); - test.equal(typeof meteorBabelHelpers.sanitizeForInObject, "function"); + test.equal(typeof meteorBabelHelpers, 'object'); + test.equal(typeof meteorBabelHelpers.sanitizeForInObject, 'function'); } class Base { constructor(...args) { this.sum = 0; - args.forEach(arg => this.sum += arg); + args.forEach(arg => (this.sum += arg)); } static inherited() { - return "inherited"; + return 'inherited'; } } @@ -345,32 +363,35 @@ Tinytest.addAsync("ecmascript - runtime - misc support", (test, done) => { } // Check that static methods are inherited. - test.equal(Derived.inherited(), "inherited"); + test.equal(Derived.inherited(), 'inherited'); const d = new Derived(); test.equal(d.sum, 6); - const expectedError = new Error("expected"); + const expectedError = new Error('expected'); - Promise.resolve("working").then(result => { - test.equal(result, "working"); - throw expectedError; - }).catch(error => { - test.equal(error, expectedError); - if (Meteor.isServer) { - const Fiber = Npm.require("fibers"); - // Make sure the Promise polyfill runs callbacks in a Fiber. - test.instanceOf(Fiber.current, Fiber); - } - }).then(done, error => test.exception(error)); + Promise.resolve('working') + .then(result => { + test.equal(result, 'working'); + throw expectedError; + }) + .catch(error => { + test.equal(error, expectedError); + if (Meteor.isServer) { + const Fiber = Npm.require('fibers'); + // Make sure the Promise polyfill runs callbacks in a Fiber. + test.instanceOf(Fiber.current, Fiber); + } + }) + .then(done, error => test.exception(error)); }); -Tinytest.addAsync("ecmascript - runtime - async fibers", (test, done) => { - if (! Meteor.isServer) { +Tinytest.addAsync('ecmascript - runtime - async fibers', (test, done) => { + if (!Meteor.isServer) { return done(); } - const Fiber = Npm.require("fibers"); + const Fiber = Npm.require('fibers'); function wait() { return new Promise(resolve => setTimeout(resolve, 10)); diff --git a/packages/modern-browsers/modern.js b/packages/modern-browsers/modern.js index 699301bdc2..01b57aefaa 100644 --- a/packages/modern-browsers/modern.js +++ b/packages/modern-browsers/modern.js @@ -6,9 +6,9 @@ const hasOwn = Object.prototype.hasOwnProperty; const browserAliases = { chrome: [ // chromeMobile*, per https://github.com/meteor/meteor/pull/9793, - "chromeMobile", - "chromeMobileIOS", - "chromeMobileWebView", + 'chromeMobile', + 'chromeMobileIOS', + 'chromeMobileWebView', // The major version number of Chromium and Headless Chrome track with the // releases of Chrome Dev, Canary and Stable, so we should be okay to @@ -18,19 +18,21 @@ const browserAliases = { // Chromium is particularly important to list here since, unlike macOS // builds, Linux builds list Chromium in the userAgent along with Chrome: // e.g. Chromium/70.0.3538.77 Chrome/70.0.3538.77 - "chromium", - "headlesschrome", + 'chromium', + 'headlesschrome', ], // If a call to setMinimumBrowserVersions specifies Edge 12 as a minimum // version, that means no version of Internet Explorer pre-Edge should // be classified as modern. This edge:["ie"] alias effectively enforces // that logic, because there is no IE12. #9818 #9839 - edge: ["ie"], + edge: ['ie'], + + firefox: ['firefoxMobile'], // The webapp package converts browser names to camel case, so // mobile_safari and mobileSafari should be synonymous. - mobile_safari: ["mobileSafari", "mobileSafariUI", "mobileSafariUI/WKWebView"], + mobile_safari: ['mobileSafari', 'mobileSafariUI', 'mobileSafariUI/WKWebView'], }; // Expand the given minimum versions by reusing chrome versions for @@ -49,7 +51,7 @@ function applyAliases(versions) { if (hasOwn.call(lowerCaseVersions, original)) { aliases.forEach(alias => { alias = alias.toLowerCase(); - if (! hasOwn.call(lowerCaseVersions, alias)) { + if (!hasOwn.call(lowerCaseVersions, alias)) { lowerCaseVersions[alias] = lowerCaseVersions[original]; } }); @@ -66,17 +68,17 @@ function applyAliases(versions) { // webapp via request.browser, return true if that browser qualifies as // "modern" according to all requested version constraints. function isModern(browser) { - const lowerCaseName = browser && - typeof browser.name === "string" && - browser.name.toLowerCase(); + const lowerCaseName = + browser && typeof browser.name === 'string' && browser.name.toLowerCase(); - return !!lowerCaseName && + return ( + !!lowerCaseName && hasOwn.call(minimumVersions, lowerCaseName) && - greaterThanOrEqualTo([ - ~~browser.major, - ~~browser.minor, - ~~browser.patch, - ], minimumVersions[lowerCaseName].version); + greaterThanOrEqualTo( + [~~browser.major, ~~browser.minor, ~~browser.patch], + minimumVersions[lowerCaseName].version + ) + ); } // Any package that depends on the modern-browsers package can call this @@ -90,22 +92,24 @@ function setMinimumBrowserVersions(versions, source) { Object.keys(lowerCaseVersions).forEach(lowerCaseName => { const version = lowerCaseVersions[lowerCaseName]; - if (hasOwn.call(minimumVersions, lowerCaseName) && - ! greaterThan(version, minimumVersions[lowerCaseName].version)) { + if ( + hasOwn.call(minimumVersions, lowerCaseName) && + !greaterThan(version, minimumVersions[lowerCaseName].version) + ) { return; } minimumVersions[lowerCaseName] = { version: copy(version), - source: source || getCaller("setMinimumBrowserVersions") + source: source || getCaller('setMinimumBrowserVersions'), }; }); } function getCaller(calleeName) { - const error = new Error; + const error = new Error(); Error.captureStackTrace(error); - const lines = error.stack.split("\n"); + const lines = error.stack.split('\n'); let caller; lines.some((line, i) => { if (line.indexOf(calleeName) >= 0) { @@ -120,17 +124,17 @@ Object.assign(exports, { isModern, setMinimumBrowserVersions, calculateHashOfMinimumVersions() { - const { createHash } = require("crypto"); - return createHash("sha1").update( - JSON.stringify(minimumVersions) - ).digest("hex"); - } + const { createHash } = require('crypto'); + return createHash('sha1') + .update(JSON.stringify(minimumVersions)) + .digest('hex'); + }, }); // For making defensive copies of [major, minor, ...] version arrays, so // they don't change unexpectedly. function copy(version) { - if (typeof version === "number") { + if (typeof version === 'number') { return version; } @@ -142,17 +146,17 @@ function copy(version) { } function greaterThanOrEqualTo(a, b) { - return ! greaterThan(b, a); + return !greaterThan(b, a); } function greaterThan(a, b) { - const as = (typeof a === "number") ? [a] : a; - const bs = (typeof b === "number") ? [b] : b; + const as = typeof a === 'number' ? [a] : a; + const bs = typeof b === 'number' ? [b] : b; const maxLen = Math.max(as.length, bs.length); for (let i = 0; i < maxLen; ++i) { - a = (i < as.length) ? as[i] : 0; - b = (i < bs.length) ? bs[i] : 0; + a = i < as.length ? as[i] : 0; + b = i < bs.length ? bs[i] : 0; if (a > b) { return true; @@ -167,49 +171,61 @@ function greaterThan(a, b) { } function makeSource(feature) { - return module.id + " (" + feature + ")"; + return module.id + ' (' + feature + ')'; } -setMinimumBrowserVersions({ - chrome: 49, - edge: 12, - firefox: 45, - mobileSafari: [9, 2], - opera: 36, - safari: 9, - // Electron 1.0.0+ matches Chromium 49, per - // https://github.com/Kilian/electron-to-chromium/blob/master/full-versions.js - electron: 1, -}, makeSource("classes")); +setMinimumBrowserVersions( + { + chrome: 49, + edge: 12, + firefox: 45, + mobileSafari: [9, 2], + opera: 36, + safari: 9, + // Electron 1.0.0+ matches Chromium 49, per + // https://github.com/Kilian/electron-to-chromium/blob/master/full-versions.js + electron: 1, + }, + makeSource('classes') +); -setMinimumBrowserVersions({ - chrome: 39, - edge: 13, - firefox: 26, - mobileSafari: 10, - opera: 26, - safari: 10, - // Disallow any version of PhantomJS. - phantomjs: Infinity, - electron: [0, 20], -}, makeSource("generator functions")); +setMinimumBrowserVersions( + { + chrome: 39, + edge: 13, + firefox: 26, + mobileSafari: 10, + opera: 26, + safari: 10, + // Disallow any version of PhantomJS. + phantomjs: Infinity, + electron: [0, 20], + }, + makeSource('generator functions') +); -setMinimumBrowserVersions({ - chrome: 41, - edge: 13, - firefox: 34, - mobileSafari: [9, 2], - opera: 29, - safari: [9, 1], - electron: [0, 24], -}, makeSource("template literals")); +setMinimumBrowserVersions( + { + chrome: 41, + edge: 13, + firefox: 34, + mobileSafari: [9, 2], + opera: 29, + safari: [9, 1], + electron: [0, 24], + }, + makeSource('template literals') +); -setMinimumBrowserVersions({ - chrome: 38, - edge: 12, - firefox: 36, - mobileSafari: 9, - opera: 25, - safari: 9, - electron: [0, 20], -}, makeSource("symbols")); +setMinimumBrowserVersions( + { + chrome: 38, + edge: 12, + firefox: 36, + mobileSafari: 9, + opera: 25, + safari: 9, + electron: [0, 20], + }, + makeSource('symbols') +); diff --git a/packages/modern-browsers/package.js b/packages/modern-browsers/package.js index 5773274865..7b01587761 100644 --- a/packages/modern-browsers/package.js +++ b/packages/modern-browsers/package.js @@ -1,19 +1,20 @@ Package.describe({ - name: "modern-browsers", - version: "0.1.6", - summary: "API for defining the boundary between modern and legacy " + - "JavaScript clients", - documentation: "README.md" + name: 'modern-browsers', + version: '0.1.7', + summary: + 'API for defining the boundary between modern and legacy ' + + 'JavaScript clients', + documentation: 'README.md', }); Package.onUse(function(api) { - api.use("modules"); - api.mainModule("modern.js", "server"); + api.use('modules'); + api.mainModule('modern.js', 'server'); }); Package.onTest(function(api) { - api.use("ecmascript"); - api.use("tinytest"); - api.use("modern-browsers"); - api.mainModule("modern-tests.js", "server"); + api.use('ecmascript'); + api.use('tinytest'); + api.use('modern-browsers'); + api.mainModule('modern-tests.js', 'server'); }); diff --git a/packages/mongo/collection.js b/packages/mongo/collection.js index 87527f9863..ad5ab93c6f 100644 --- a/packages/mongo/collection.js +++ b/packages/mongo/collection.js @@ -25,16 +25,19 @@ The default id generation technique is `'STRING'`. * @param {Boolean} options.defineMutationMethods Set to `false` to skip setting up the mutation methods that enable insert/update/remove from client code. Default `true`. */ Mongo.Collection = function Collection(name, options) { - if (!name && (name !== null)) { - Meteor._debug("Warning: creating anonymous collection. It will not be " + - "saved or synchronized over the network. (Pass null for " + - "the collection name to turn off this warning.)"); + if (!name && name !== null) { + Meteor._debug( + 'Warning: creating anonymous collection. It will not be ' + + 'saved or synchronized over the network. (Pass null for ' + + 'the collection name to turn off this warning.)' + ); name = null; } - if (name !== null && typeof name !== "string") { + if (name !== null && typeof name !== 'string') { throw new Error( - "First argument to new Mongo.Collection must be a string or null"); + 'First argument to new Mongo.Collection must be a string or null' + ); } if (options && options.methods) { @@ -42,7 +45,7 @@ Mongo.Collection = function Collection(name, options) { // "connection" directly instead of in options. (Connections must have a "methods" // method.) // XXX remove before 1.0 - options = {connection: options}; + options = { connection: options }; } // Backwards compatibility: "connection" used to be called "manager". if (options && options.manager && !options.connection) { @@ -55,49 +58,52 @@ Mongo.Collection = function Collection(name, options) { transform: null, _driver: undefined, _preventAutopublish: false, - ...options, + ...options, }; switch (options.idGeneration) { - case 'MONGO': - this._makeNewID = function () { - var src = name ? DDP.randomStream('/collection/' + name) : Random.insecure; - return new Mongo.ObjectID(src.hexString(24)); - }; - break; - case 'STRING': - default: - this._makeNewID = function () { - var src = name ? DDP.randomStream('/collection/' + name) : Random.insecure; - return src.id(); - }; - break; + case 'MONGO': + this._makeNewID = function() { + var src = name + ? DDP.randomStream('/collection/' + name) + : Random.insecure; + return new Mongo.ObjectID(src.hexString(24)); + }; + break; + case 'STRING': + default: + this._makeNewID = function() { + var src = name + ? DDP.randomStream('/collection/' + name) + : Random.insecure; + return src.id(); + }; + break; } this._transform = LocalCollection.wrapTransform(options.transform); - if (! name || options.connection === null) + if (!name || options.connection === null) // note: nameless collections never have a connection this._connection = null; - else if (options.connection) - this._connection = options.connection; - else if (Meteor.isClient) - this._connection = Meteor.connection; - else - this._connection = Meteor.server; + else if (options.connection) this._connection = options.connection; + else if (Meteor.isClient) this._connection = Meteor.connection; + else this._connection = Meteor.server; if (!options._driver) { // XXX This check assumes that webapp is loaded so that Meteor.server !== // null. We should fully support the case of "want to use a Mongo-backed // collection from Node code without webapp", but we don't yet. // #MeteorServerNull - if (name && this._connection === Meteor.server && - typeof MongoInternals !== "undefined" && - MongoInternals.defaultRemoteCollectionDriver) { + if ( + name && + this._connection === Meteor.server && + typeof MongoInternals !== 'undefined' && + MongoInternals.defaultRemoteCollectionDriver + ) { options._driver = MongoInternals.defaultRemoteCollectionDriver(); } else { - const { LocalCollectionDriver } = - require("./local_collection_driver.js"); + const { LocalCollectionDriver } = require('./local_collection_driver.js'); options._driver = LocalCollectionDriver; } } @@ -114,21 +120,25 @@ Mongo.Collection = function Collection(name, options) { if (options.defineMutationMethods !== false) { try { this._defineMutationMethods({ - useExisting: options._suppressSameNameError === true + useExisting: options._suppressSameNameError === true, }); } catch (error) { // Throw a more understandable error on the server for same collection name - if (error.message === `A method named '/${name}/insert' is already defined`) + if ( + error.message === `A method named '/${name}/insert' is already defined` + ) throw new Error(`There is already a collection named "${name}"`); throw error; } } // autopublish - if (Package.autopublish && - ! options._preventAutopublish && - this._connection && - this._connection.publish) { + if ( + Package.autopublish && + !options._preventAutopublish && + this._connection && + this._connection.publish + ) { this._connection.publish(null, () => this.find(), { is_auto: true, }); @@ -136,12 +146,9 @@ Mongo.Collection = function Collection(name, options) { }; Object.assign(Mongo.Collection.prototype, { - _maybeSetUpReplication(name, { - _suppressSameNameError = false - }) { + _maybeSetUpReplication(name, { _suppressSameNameError = false }) { const self = this; - if (! (self._connection && - self._connection.registerStore)) { + if (!(self._connection && self._connection.registerStore)) { return; } @@ -165,11 +172,9 @@ Object.assign(Mongo.Collection.prototype, { // stage), and so that a re-sorting of a query can take advantage of the // full _diffQuery moved calculation instead of applying change one at a // time. - if (batchSize > 1 || reset) - self._collection.pauseObservers(); + if (batchSize > 1 || reset) self._collection.pauseObservers(); - if (reset) - self._collection.remove({}); + if (reset) self._collection.remove({}); }, // Apply an update. @@ -211,8 +216,7 @@ Object.assign(Mongo.Collection.prototype, { if (msg.msg === 'replace') { var replace = msg.replace; if (!replace) { - if (doc) - self._collection.remove(mongoId); + if (doc) self._collection.remove(mongoId); } else if (!doc) { self._collection.insert(replace); } else { @@ -222,16 +226,19 @@ Object.assign(Mongo.Collection.prototype, { return; } else if (msg.msg === 'added') { if (doc) { - throw new Error("Expected not to find a document already present for an add"); + throw new Error( + 'Expected not to find a document already present for an add' + ); } self._collection.insert({ _id: mongoId, ...msg.fields }); } else if (msg.msg === 'removed') { if (!doc) - throw new Error("Expected to find a document already present for removed"); + throw new Error( + 'Expected to find a document already present for removed' + ); self._collection.remove(mongoId); } else if (msg.msg === 'changed') { - if (!doc) - throw new Error("Expected to find a document to change"); + if (!doc) throw new Error('Expected to find a document to change'); const keys = Object.keys(msg.fields); if (keys.length > 0) { var modifier = {}; @@ -240,7 +247,7 @@ Object.assign(Mongo.Collection.prototype, { if (EJSON.equals(doc[key], value)) { return; } - if (typeof value === "undefined") { + if (typeof value === 'undefined') { if (!modifier.$unset) { modifier.$unset = {}; } @@ -283,10 +290,10 @@ Object.assign(Mongo.Collection.prototype, { // To be able to get back to the collection from the store. _getCollection() { return self; - } + }, }); - if (! ok) { + if (!ok) { const message = `There is already a collection named "${name}"`; if (_suppressSameNameError === true) { // XXX In theory we do not have to throw when `ok` is falsy. The @@ -308,10 +315,8 @@ Object.assign(Mongo.Collection.prototype, { /// _getFindSelector(args) { - if (args.length == 0) - return {}; - else - return args[0]; + if (args.length == 0) return {}; + else return args[0]; }, _getFindOptions(args) { @@ -319,12 +324,19 @@ Object.assign(Mongo.Collection.prototype, { if (args.length < 2) { return { transform: self._transform }; } else { - check(args[1], Match.Optional(Match.ObjectIncluding({ - fields: Match.Optional(Match.OneOf(Object, undefined)), - sort: Match.Optional(Match.OneOf(Object, Array, Function, undefined)), - limit: Match.Optional(Match.OneOf(Number, undefined)), - skip: Match.Optional(Match.OneOf(Number, undefined)) - }))); + check( + args[1], + Match.Optional( + Match.ObjectIncluding({ + fields: Match.Optional(Match.OneOf(Object, undefined)), + sort: Match.Optional( + Match.OneOf(Object, Array, Function, undefined) + ), + limit: Match.Optional(Match.OneOf(Number, undefined)), + skip: Match.Optional(Match.OneOf(Number, undefined)), + }) + ) + ); return { transform: self._transform, @@ -386,31 +398,33 @@ Object.assign(Mongo.Collection.prototype, { this._getFindSelector(args), this._getFindOptions(args) ); - } + }, }); Object.assign(Mongo.Collection, { _publishCursor(cursor, sub, collection) { - var observeHandle = cursor.observeChanges({ - added: function (id, fields) { - sub.added(collection, id, fields); + var observeHandle = cursor.observeChanges( + { + added: function(id, fields) { + sub.added(collection, id, fields); + }, + changed: function(id, fields) { + sub.changed(collection, id, fields); + }, + removed: function(id) { + sub.removed(collection, id); + }, }, - changed: function (id, fields) { - sub.changed(collection, id, fields); - }, - removed: function (id) { - sub.removed(collection, id); - } - }, - // Publications don't mutate the documents - // This is tested by the `livedata - publish callbacks clone` test - { nonMutatingCallbacks: true }); + // Publications don't mutate the documents + // This is tested by the `livedata - publish callbacks clone` test + { nonMutatingCallbacks: true } + ); // We don't call sub.ready() here: it gets called in livedata_server, after // possibly calling _publishCursor on multiple returned cursors. // register stop callback (expects lambda w/ no args). - sub.onStop(function () { + sub.onStop(function() { observeHandle.stop(); }); @@ -425,8 +439,7 @@ Object.assign(Mongo.Collection, { // instead. _rewriteSelector(selector, { fallbackId } = {}) { // shorthand -- scalars match _id - if (LocalCollection._selectorIsId(selector)) - selector = {_id: selector}; + if (LocalCollection._selectorIsId(selector)) selector = { _id: selector }; if (Array.isArray(selector)) { // This is consistent with the Mongo console itself; if we don't do this @@ -434,13 +447,13 @@ Object.assign(Mongo.Collection, { throw new Error("Mongo selector can't be an array."); } - if (!selector || (('_id' in selector) && !selector._id)) { + if (!selector || ('_id' in selector && !selector._id)) { // can't match anything return { _id: fallbackId || Random.id() }; } return selector; - } + }, }); Object.assign(Mongo.Collection.prototype, { @@ -486,7 +499,7 @@ Object.assign(Mongo.Collection.prototype, { insert(doc, callback) { // Make sure we were passed a document to insert if (!doc) { - throw new Error("insert requires an argument"); + throw new Error('insert requires an argument'); } // Make a shallow clone of the document, preserving its prototype. @@ -496,11 +509,13 @@ Object.assign(Mongo.Collection.prototype, { ); if ('_id' in doc) { - if (! doc._id || - ! (typeof doc._id === 'string' || - doc._id instanceof Mongo.ObjectID)) { + if ( + !doc._id || + !(typeof doc._id === 'string' || doc._id instanceof Mongo.ObjectID) + ) { throw new Error( - "Meteor requires document _id fields to be non-empty strings or ObjectIDs"); + 'Meteor requires document _id fields to be non-empty strings or ObjectIDs' + ); } } else { let generateId = true; @@ -522,7 +537,7 @@ Object.assign(Mongo.Collection.prototype, { // On inserts, always return the id that we generated; on all other // operations, just return the result from the collection. - var chooseReturnValueFromCollectionResult = function (result) { + var chooseReturnValueFromCollectionResult = function(result) { if (doc._id) { return doc._id; } @@ -536,10 +551,12 @@ Object.assign(Mongo.Collection.prototype, { }; const wrappedCallback = wrapCallback( - callback, chooseReturnValueFromCollectionResult); + callback, + chooseReturnValueFromCollectionResult + ); if (this._isRemoteCollection()) { - const result = this._callMutatorMethod("insert", [doc], wrappedCallback); + const result = this._callMutatorMethod('insert', [doc], wrappedCallback); return chooseReturnValueFromCollectionResult(result); } @@ -584,8 +601,13 @@ Object.assign(Mongo.Collection.prototype, { if (options && options.upsert) { // set `insertedId` if absent. `insertedId` is a Meteor extension. if (options.insertedId) { - if (!(typeof options.insertedId === 'string' || options.insertedId instanceof Mongo.ObjectID)) - throw new Error("insertedId must be string or ObjectID"); + if ( + !( + typeof options.insertedId === 'string' || + options.insertedId instanceof Mongo.ObjectID + ) + ) + throw new Error('insertedId must be string or ObjectID'); insertedId = options.insertedId; } else if (!selector || !selector._id) { insertedId = this._makeNewID(); @@ -594,19 +616,16 @@ Object.assign(Mongo.Collection.prototype, { } } - selector = - Mongo.Collection._rewriteSelector(selector, { fallbackId: insertedId }); + selector = Mongo.Collection._rewriteSelector(selector, { + fallbackId: insertedId, + }); const wrappedCallback = wrapCallback(callback); if (this._isRemoteCollection()) { - const args = [ - selector, - modifier, - options - ]; + const args = [selector, modifier, options]; - return this._callMutatorMethod("update", args, wrappedCallback); + return this._callMutatorMethod('update', args, wrappedCallback); } // it's my collection. descend into the collection object @@ -616,7 +635,11 @@ Object.assign(Mongo.Collection.prototype, { // operation asynchronously, then queryRet will be undefined, and the // result will be returned through the callback instead. return this._collection.update( - selector, modifier, options, wrappedCallback); + selector, + modifier, + options, + wrappedCallback + ); } catch (e) { if (callback) { callback(e); @@ -641,7 +664,7 @@ Object.assign(Mongo.Collection.prototype, { const wrappedCallback = wrapCallback(callback); if (this._isRemoteCollection()) { - return this._callMutatorMethod("remove", [selector], wrappedCallback); + return this._callMutatorMethod('remove', [selector], wrappedCallback); } // it's my collection. descend into the collection object @@ -680,16 +703,21 @@ Object.assign(Mongo.Collection.prototype, { * @param {Function} [callback] Optional. If present, called with an error object as the first argument and, if no error, the number of affected documents as the second. */ upsert(selector, modifier, options, callback) { - if (! callback && typeof options === "function") { + if (!callback && typeof options === 'function') { callback = options; options = {}; } - return this.update(selector, modifier, { - ...options, - _returnObject: true, - upsert: true, - }, callback); + return this.update( + selector, + modifier, + { + ...options, + _returnObject: true, + upsert: true, + }, + callback + ); }, // We'll actually design an index API later. For now, we just pass through to @@ -697,7 +725,7 @@ Object.assign(Mongo.Collection.prototype, { _ensureIndex(index, options) { var self = this; if (!self._collection._ensureIndex || !self._collection.createIndex) - throw new Error("Can only call createIndex on server collections"); + throw new Error('Can only call createIndex on server collections'); // TODO enable this message a release before we will remove this function // import { Log } from 'meteor/logging'; // Log.debug(`_ensureIndex has been deprecated, please use the new 'createIndex' instead${options?.name ? `, index name: ${options.name}` : `, index: ${JSON.stringify(index)}`}`) @@ -715,7 +743,7 @@ Object.assign(Mongo.Collection.prototype, { * @memberof Mongo.Collection * @instance * @param {Object} index A document that contains the field and value pairs where the field is the index key and the value describes the type of index for that field. For an ascending index on a field, specify a value of `1`; for descending index, specify a value of `-1`. Use `text` for text indexes. - * @param {Object} [options] All options are listed in [MongoDB documentation](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#std-label-ensureIndex-options) + * @param {Object} [options] All options are listed in [MongoDB documentation](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#options) * @param {String} options.name Name of the index * @param {Boolean} options.unique Define that the index values must be unique, more at [MongoDB documentation](https://docs.mongodb.com/manual/core/index-unique/) * @param {Boolean} options.sparse Define that the index is sparse, more at [MongoDB documentation](https://docs.mongodb.com/manual/core/index-sparse/) @@ -723,28 +751,30 @@ Object.assign(Mongo.Collection.prototype, { createIndex(index, options) { var self = this; if (!self._collection.createIndex) - throw new Error("Can only call createIndex on server collections"); + throw new Error('Can only call createIndex on server collections'); self._collection.createIndex(index, options); }, _dropIndex(index) { var self = this; if (!self._collection._dropIndex) - throw new Error("Can only call _dropIndex on server collections"); + throw new Error('Can only call _dropIndex on server collections'); self._collection._dropIndex(index); }, _dropCollection() { var self = this; if (!self._collection.dropCollection) - throw new Error("Can only call _dropCollection on server collections"); + throw new Error('Can only call _dropCollection on server collections'); self._collection.dropCollection(); }, _createCappedCollection(byteSize, maxDocuments) { var self = this; if (!self._collection._createCappedCollection) - throw new Error("Can only call _createCappedCollection on server collections"); + throw new Error( + 'Can only call _createCappedCollection on server collections' + ); self._collection._createCappedCollection(byteSize, maxDocuments); }, @@ -756,8 +786,8 @@ Object.assign(Mongo.Collection.prototype, { */ rawCollection() { var self = this; - if (! self._collection.rawCollection) { - throw new Error("Can only call rawCollection on server collections"); + if (!self._collection.rawCollection) { + throw new Error('Can only call rawCollection on server collections'); } return self._collection.rawCollection(); }, @@ -770,24 +800,27 @@ Object.assign(Mongo.Collection.prototype, { */ rawDatabase() { var self = this; - if (! (self._driver.mongo && self._driver.mongo.db)) { - throw new Error("Can only call rawDatabase on server collections"); + if (!(self._driver.mongo && self._driver.mongo.db)) { + throw new Error('Can only call rawDatabase on server collections'); } return self._driver.mongo.db; - } + }, }); // Convert the callback to not return a result if there is an error function wrapCallback(callback, convertResult) { - return callback && function (error, result) { - if (error) { - callback(error); - } else if (typeof convertResult === "function") { - callback(error, convertResult(result)); - } else { - callback(error, result); + return ( + callback && + function(error, result) { + if (error) { + callback(error); + } else if (typeof convertResult === 'function') { + callback(error, convertResult(result)); + } else { + callback(error, result); + } } - }; + ); } /** @@ -821,17 +854,16 @@ Mongo.Collection.ObjectID = Mongo.ObjectID; Meteor.Collection = Mongo.Collection; // Allow deny stuff is now in the allow-deny package -Object.assign( - Meteor.Collection.prototype, - AllowDeny.CollectionPrototype -); +Object.assign(Meteor.Collection.prototype, AllowDeny.CollectionPrototype); function popCallbackFromArgs(args) { // Pull off any callback (or perhaps a 'callback' variable that was passed // in undefined, like how 'upsert' does it). - if (args.length && - (args[args.length - 1] === undefined || - args[args.length - 1] instanceof Function)) { + if ( + args.length && + (args[args.length - 1] === undefined || + args[args.length - 1] instanceof Function) + ) { return args.pop(); } } diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index 9b34f25706..8b926afdc7 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -1,35 +1,28 @@ -import assert from "assert"; -import { - readFileSync, - chmodSync, - chownSync -} from "fs"; -import { createServer } from "http"; -import { userInfo } from "os"; -import { - join as pathJoin, - dirname as pathDirname, -} from "path"; -import { parse as parseUrl } from "url"; -import { createHash } from "crypto"; -import { connect } from "./connect.js"; -import compress from "compression"; -import cookieParser from "cookie-parser"; -import qs from "qs"; -import parseRequest from "parseurl"; -import basicAuth from "basic-auth-connect"; -import { lookup as lookupUserAgent } from "useragent"; -import { isModern } from "meteor/modern-browsers"; -import send from "send"; +import assert from 'assert'; +import { readFileSync, chmodSync, chownSync } from 'fs'; +import { createServer } from 'http'; +import { userInfo } from 'os'; +import { join as pathJoin, dirname as pathDirname } from 'path'; +import { parse as parseUrl } from 'url'; +import { createHash } from 'crypto'; +import { connect } from './connect.js'; +import compress from 'compression'; +import cookieParser from 'cookie-parser'; +import qs from 'qs'; +import parseRequest from 'parseurl'; +import basicAuth from 'basic-auth-connect'; +import { lookup as lookupUserAgent } from 'useragent'; +import { isModern } from 'meteor/modern-browsers'; +import send from 'send'; import { removeExistingSocketFile, registerSocketFileCleanup, } from './socket_file.js'; -import cluster from "cluster"; -import whomst from "@vlasky/whomst"; +import cluster from 'cluster'; +import whomst from '@vlasky/whomst'; -var SHORT_SOCKET_TIMEOUT = 5*1000; -var LONG_SOCKET_TIMEOUT = 120*1000; +var SHORT_SOCKET_TIMEOUT = 5 * 1000; +var LONG_SOCKET_TIMEOUT = 120 * 1000; export const WebApp = {}; export const WebAppInternals = {}; @@ -43,7 +36,7 @@ WebAppInternals.NpmModules = { connect: { version: Npm.require('connect/package.json').version, module: connect, - } + }, }; // Though we might prefer to use web.browser (modern) as the default @@ -56,13 +49,12 @@ WebApp.clientPrograms = {}; // XXX maps archs to program path on filesystem var archPath = {}; -var bundledJsCssUrlRewriteHook = function (url) { - var bundledPrefix = - __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || ''; +var bundledJsCssUrlRewriteHook = function(url) { + var bundledPrefix = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || ''; return bundledPrefix + url; }; -var sha1 = function (contents) { +var sha1 = function(contents) { var hash = createHash('sha1'); hash.update(contents); return hash.digest('hex'); @@ -112,41 +104,41 @@ function shouldCompress(req, res) { // Real routing / server side rendering will probably refactor this // heavily. - // e.g. "Mobile Safari" => "mobileSafari" -var camelCase = function (name) { +var camelCase = function(name) { var parts = name.split(' '); parts[0] = parts[0].toLowerCase(); - for (var i = 1; i < parts.length; ++i) { + for (var i = 1; i < parts.length; ++i) { parts[i] = parts[i].charAt(0).toUpperCase() + parts[i].substr(1); } return parts.join(''); }; -var identifyBrowser = function (userAgentString) { +var identifyBrowser = function(userAgentString) { var userAgent = lookupUserAgent(userAgentString); return { name: camelCase(userAgent.family), major: +userAgent.major, minor: +userAgent.minor, - patch: +userAgent.patch + patch: +userAgent.patch, }; }; // XXX Refactor as part of implementing real routing. WebAppInternals.identifyBrowser = identifyBrowser; -WebApp.categorizeRequest = function (req) { - if (req.browser && req.arch && typeof req.modern === "boolean") { +WebApp.categorizeRequest = function(req) { + if (req.browser && req.arch && typeof req.modern === 'boolean') { // Already categorized. return req; } - const browser = identifyBrowser(req.headers["user-agent"]); + const browser = identifyBrowser(req.headers['user-agent']); const modern = isModern(browser); - const path = typeof req.pathname === "string" - ? req.pathname - : parseRequest(req).pathname; + const path = + typeof req.pathname === 'string' + ? req.pathname + : parseRequest(req).pathname; const categorized = { browser, @@ -160,16 +152,16 @@ WebApp.categorizeRequest = function (req) { cookies: req.cookies, }; - const pathParts = path.split("/"); + const pathParts = path.split('/'); const archKey = pathParts[1]; - if (archKey.startsWith("__")) { - const archCleaned = "web." + archKey.slice(2); + if (archKey.startsWith('__')) { + const archCleaned = 'web.' + archKey.slice(2); if (hasOwn.call(WebApp.clientPrograms, archCleaned)) { pathParts.splice(1, 1); // Remove the archKey part. return Object.assign(categorized, { arch: archCleaned, - path: pathParts.join("/"), + path: pathParts.join('/'), }); } } @@ -177,8 +169,8 @@ WebApp.categorizeRequest = function (req) { // TODO Perhaps one day we could infer Cordova clients here, so that we // wouldn't have to use prefixed "/__cordova/..." URLs. const preferredArchOrder = isModern(browser) - ? ["web.browser", "web.browser.legacy"] - : ["web.browser.legacy", "web.browser"]; + ? ['web.browser', 'web.browser.legacy'] + : ['web.browser.legacy', 'web.browser']; for (const arch of preferredArchOrder) { // If our preferred arch is not available, it's better to use another @@ -200,26 +192,24 @@ WebApp.categorizeRequest = function (req) { // be added to the '' tag. Each function is passed a 'request' object (see // #BrowserIdentification) and should return null or object. var htmlAttributeHooks = []; -var getHtmlAttributes = function (request) { - var combinedAttributes = {}; - _.each(htmlAttributeHooks || [], function (hook) { +var getHtmlAttributes = function(request) { + var combinedAttributes = {}; + _.each(htmlAttributeHooks || [], function(hook) { var attributes = hook(request); - if (attributes === null) - return; + if (attributes === null) return; if (typeof attributes !== 'object') - throw Error("HTML attribute hook must return null or object"); + throw Error('HTML attribute hook must return null or object'); _.extend(combinedAttributes, attributes); }); return combinedAttributes; }; -WebApp.addHtmlAttributeHook = function (hook) { +WebApp.addHtmlAttributeHook = function(hook) { htmlAttributeHooks.push(hook); }; // Serve app HTML for this URL? -var appUrl = function (url) { - if (url === '/favicon.ico' || url === '/robots.txt') - return false; +var appUrl = function(url) { + if (url === '/favicon.ico' || url === '/robots.txt') return false; // NOTE: app.manifest is not a web standard like favicon.ico and // robots.txt. It is a file name we have chosen to use for HTML5 @@ -227,18 +217,15 @@ var appUrl = function (url) { // then removing it from poisoning an app permanently. Eventually, // once we have server side routing, this won't be needed as // unknown URLs with return a 404 automatically. - if (url === '/app.manifest') - return false; + if (url === '/app.manifest') return false; // Avoid serving app HTML for declared routes such as /sockjs/. - if (RoutePolicy.classify(url)) - return false; + if (RoutePolicy.classify(url)) return false; // we currently return app HTML on all URLs by default return true; }; - // We need to calculate the client hash after all packages have loaded // to give them a chance to populate __meteor_runtime_config__. // @@ -256,36 +243,32 @@ var appUrl = function (url) { // pre-listen" hook to allow it to insert the auto update version at // the right moment. -Meteor.startup(function () { +Meteor.startup(function() { function getter(key) { - return function (arch) { + return function(arch) { arch = arch || WebApp.defaultArch; const program = WebApp.clientPrograms[arch]; const value = program && program[key]; // If this is the first time we have calculated this hash, // program[key] will be a thunk (lazy function with no parameters) // that we should call to do the actual computation. - return typeof value === "function" - ? program[key] = value() - : value; + return typeof value === 'function' ? (program[key] = value()) : value; }; } - WebApp.calculateClientHash = WebApp.clientHash = getter("version"); - WebApp.calculateClientHashRefreshable = getter("versionRefreshable"); - WebApp.calculateClientHashNonRefreshable = getter("versionNonRefreshable"); - WebApp.calculateClientHashReplaceable = getter("versionReplaceable"); - WebApp.getRefreshableAssets = getter("refreshableAssets"); + WebApp.calculateClientHash = WebApp.clientHash = getter('version'); + WebApp.calculateClientHashRefreshable = getter('versionRefreshable'); + WebApp.calculateClientHashNonRefreshable = getter('versionNonRefreshable'); + WebApp.calculateClientHashReplaceable = getter('versionReplaceable'); + WebApp.getRefreshableAssets = getter('refreshableAssets'); }); - - // When we have a request pending, we want the socket timeout to be long, to // give ourselves a while to serve it, and to allow sockjs long polls to // complete. On the other hand, we want to close idle sockets relatively // quickly, so that we can shut down relatively promptly but cleanly, without // cutting off anyone's response. -WebApp._timeoutAdjustmentRequestCallback = function (req, res) { +WebApp._timeoutAdjustmentRequestCallback = function(req, res) { // this is really just req.socket.setTimeout(LONG_SOCKET_TIMEOUT); req.setTimeout(LONG_SOCKET_TIMEOUT); // Insert our new finish listener to run BEFORE the existing one which removes @@ -296,13 +279,14 @@ WebApp._timeoutAdjustmentRequestCallback = function (req, res) { // But it has switched back to 'finish' in Node v4: // https://github.com/nodejs/node/pull/1411 res.removeAllListeners('finish'); - res.on('finish', function () { + res.on('finish', function() { res.setTimeout(SHORT_SOCKET_TIMEOUT); }); - _.each(finishListeners, function (l) { res.on('finish', l); }); + _.each(finishListeners, function(l) { + res.on('finish', l); + }); }; - // Will be updated by main before we listen. // Map from client arch to boilerplate object. // Boilerplate object has: @@ -318,10 +302,10 @@ var boilerplateByArch = {}; // changes affecting the boilerplate. Passing null deletes the callback. // Any previous callback registered for this key will be returned. const boilerplateDataCallbacks = Object.create(null); -WebAppInternals.registerBoilerplateDataCallback = function (key, callback) { +WebAppInternals.registerBoilerplateDataCallback = function(key, callback) { const previousCallback = boilerplateDataCallbacks[key]; - if (typeof callback === "function") { + if (typeof callback === 'function') { boilerplateDataCallbacks[key] = callback; } else { assert.strictEqual(callback, null); @@ -351,10 +335,10 @@ function getBoilerplate(request, arch) { * @locus Server * @param {Object} rtimeConfig * @returns {String} -*/ -WebApp.encodeRuntimeConfig = function (rtimeConfig) { + */ +WebApp.encodeRuntimeConfig = function(rtimeConfig) { return JSON.stringify(encodeURIComponent(JSON.stringify(rtimeConfig))); -} +}; /** * @summary Takes an encoded runtime string and returns @@ -362,19 +346,19 @@ WebApp.encodeRuntimeConfig = function (rtimeConfig) { * @locus Server * @param {String} rtimeConfigString * @returns {Object} -*/ -WebApp.decodeRuntimeConfig = function (rtimeConfigStr) { + */ +WebApp.decodeRuntimeConfig = function(rtimeConfigStr) { return JSON.parse(decodeURIComponent(JSON.parse(rtimeConfigStr))); -} +}; - const runtimeConfig = { +const runtimeConfig = { // hooks will contain the callback functions // set by the caller to addRuntimeConfigHook hooks: new Hook(), // updateHooks will contain the callback functions // set by the caller to addUpdatedNotifyHook updateHooks: new Hook(), - // isUpdatedByArch is an object containing fields for each arch + // isUpdatedByArch is an object containing fields for each arch // that this server supports. // - Each field will be true when the server updates the runtimeConfig for that arch. // - When the hook callback is called the update field in the callback object will be @@ -382,7 +366,7 @@ WebApp.decodeRuntimeConfig = function (rtimeConfigStr) { // = isUpdatedyByArch[arch] is reset to false after the callback. // This enables the caller to cache data efficiently so they do not need to // decode & update data on every callback when the runtimeConfig is not changing. - isUpdatedByArch: {} + isUpdatedByArch: {}, }; /** @@ -390,17 +374,17 @@ WebApp.decodeRuntimeConfig = function (rtimeConfigStr) { * @locus Server * @isprototype true * @summary Callback for `addRuntimeConfigHook`. - * + * * If the handler returns a _falsy_ value the hook will not * modify the runtime configuration. - * + * * If the handler returns a _String_ the hook will substitute * the string for the encoded configuration string. - * + * * **Warning:** the hook does not check the return value at all it is * the responsibility of the caller to get the formatting correct using * the helper functions. - * + * * `addRuntimeConfigHookCallback` takes only one `Object` argument * with the following fields: * @param {Object} options @@ -421,7 +405,7 @@ WebApp.decodeRuntimeConfig = function (rtimeConfigStr) { /** * @summary Hook that calls back when the meteor runtime configuration, * `__meteor_runtime_config__` is being sent to any client. - * + * * **returns**: _Object_ `{ stop: function, callback: function }` * - `stop` _Function_ Call `stop()` to stop getting callbacks. * - `callback` _Function_ The passed in `callback`. @@ -431,41 +415,50 @@ WebApp.decodeRuntimeConfig = function (rtimeConfigStr) { * @returns {Object} {{ stop: function, callback: function }} * Call the returned `stop()` to stop getting callbacks. * The passed in `callback` is returned also. -*/ -WebApp.addRuntimeConfigHook = function (callback) { + */ +WebApp.addRuntimeConfigHook = function(callback) { return runtimeConfig.hooks.register(callback); -} +}; function getBoilerplateAsync(request, arch) { let boilerplate = boilerplateByArch[arch]; - runtimeConfig.hooks.forEach((hook) => { + runtimeConfig.hooks.forEach(hook => { const meteorRuntimeConfig = hook({ arch, request, encodedCurrentConfig: boilerplate.baseData.meteorRuntimeConfig, - updated: runtimeConfig.isUpdatedByArch[arch] + updated: runtimeConfig.isUpdatedByArch[arch], + }); + if (!meteorRuntimeConfig) return; + boilerplate.baseData = Object.assign({}, boilerplate.baseData, { + meteorRuntimeConfig, }); - if(!meteorRuntimeConfig) return; - boilerplate.baseData = Object.assign({}, boilerplate.baseData, {meteorRuntimeConfig}); }); runtimeConfig.isUpdatedByArch[arch] = false; - const data = Object.assign({}, boilerplate.baseData, { - htmlAttributes: getHtmlAttributes(request), - }, _.pick(request, "dynamicHead", "dynamicBody")); + const data = Object.assign( + {}, + boilerplate.baseData, + { + htmlAttributes: getHtmlAttributes(request), + }, + _.pick(request, 'dynamicHead', 'dynamicBody') + ); let madeChanges = false; let promise = Promise.resolve(); Object.keys(boilerplateDataCallbacks).forEach(key => { - promise = promise.then(() => { - const callback = boilerplateDataCallbacks[key]; - return callback(request, data, arch); - }).then(result => { - // Callbacks should return false if they did not make any changes. - if (result !== false) { - madeChanges = true; - } - }); + promise = promise + .then(() => { + const callback = boilerplateDataCallbacks[key]; + return callback(request, data, arch); + }) + .then(result => { + // Callbacks should return false if they did not make any changes. + if (result !== false) { + madeChanges = true; + } + }); }); return promise.then(() => ({ @@ -489,67 +482,76 @@ function getBoilerplateAsync(request, arch) { * object for this `arch`. */ - /** * @summary Hook that runs when the meteor runtime configuration * is updated. Typically the configuration only changes during development mode. * @locus Server - * @param {addUpdatedNotifyHookCallback} handler + * @param {addUpdatedNotifyHookCallback} handler * The `handler` is called on every change to an `arch` runtime configuration. * See `addUpdatedNotifyHookCallback`. * @returns {Object} {{ stop: function, callback: function }} -*/ + */ WebApp.addUpdatedNotifyHook = function(handler) { return runtimeConfig.updateHooks.register(handler); -} +}; -WebAppInternals.generateBoilerplateInstance = function (arch, - manifest, - additionalOptions) { +WebAppInternals.generateBoilerplateInstance = function( + arch, + manifest, + additionalOptions +) { additionalOptions = additionalOptions || {}; runtimeConfig.isUpdatedByArch[arch] = true; const rtimeConfig = { ...__meteor_runtime_config__, - ...(additionalOptions.runtimeConfigOverrides || {}) + ...(additionalOptions.runtimeConfigOverrides || {}), }; - runtimeConfig.updateHooks.forEach((cb) => { - cb({arch, manifest, runtimeConfig: rtimeConfig}); + runtimeConfig.updateHooks.forEach(cb => { + cb({ arch, manifest, runtimeConfig: rtimeConfig }); }); const meteorRuntimeConfig = JSON.stringify( encodeURIComponent(JSON.stringify(rtimeConfig)) ); - return new Boilerplate(arch, manifest, _.extend({ - pathMapper(itemPath) { - return pathJoin(archPath[arch], itemPath); - }, - baseDataExtension: { - additionalStaticJs: _.map( - additionalStaticJs || [], - function (contents, pathname) { - return { - pathname: pathname, - contents: contents - }; - } - ), - // Convert to a JSON string, then get rid of most weird characters, then - // wrap in double quotes. (The outermost JSON.stringify really ought to - // just be "wrap in double quotes" but we use it to be safe.) This might - // end up inside a ", but normal {{spacebars}} escaping escapes too much! See - // https://github.com/meteor/meteor/issues/3730 - meteorRuntimeConfig, - meteorRuntimeHash: sha1(meteorRuntimeConfig), - rootUrlPathPrefix: __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '', - bundledJsCssUrlRewriteHook: bundledJsCssUrlRewriteHook, - sriMode: sriMode, - inlineScriptsAllowed: WebAppInternals.inlineScriptsAllowed(), - inline: additionalOptions.inline - } - }, additionalOptions)); + return new Boilerplate( + arch, + manifest, + Object.assign( + { + pathMapper(itemPath) { + return pathJoin(archPath[arch], itemPath); + }, + baseDataExtension: { + additionalStaticJs: _.map(additionalStaticJs || [], function( + contents, + pathname + ) { + return { + pathname: pathname, + contents: contents, + }; + }), + // Convert to a JSON string, then get rid of most weird characters, then + // wrap in double quotes. (The outermost JSON.stringify really ought to + // just be "wrap in double quotes" but we use it to be safe.) This might + // end up inside a ", but normal {{spacebars}} escaping escapes too much! See + // https://github.com/meteor/meteor/issues/3730 + meteorRuntimeConfig, + meteorRuntimeHash: sha1(meteorRuntimeConfig), + rootUrlPathPrefix: + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '', + bundledJsCssUrlRewriteHook: bundledJsCssUrlRewriteHook, + sriMode: sriMode, + inlineScriptsAllowed: WebAppInternals.inlineScriptsAllowed(), + inline: additionalOptions.inline, + }, + }, + additionalOptions + ) + ); }; // A mapping from url path to architecture (e.g. "web.browser") to static @@ -564,11 +566,11 @@ WebAppInternals.generateBoilerplateInstance = function (arch, // Serve static files from the manifest or added with // `addStaticJs`. Exported for tests. -WebAppInternals.staticFilesMiddleware = async function ( +WebAppInternals.staticFilesMiddleware = async function( staticFilesByArch, req, res, - next, + next ) { var pathname = parseRequest(req).pathname; try { @@ -578,8 +580,12 @@ WebAppInternals.staticFilesMiddleware = async function ( return; } - var serveStaticJs = function (s) { - if (req.method === 'GET' || req.method === 'HEAD') { + var serveStaticJs = function(s) { + if ( + req.method === 'GET' || + req.method === 'HEAD' || + Meteor.settings.packages?.webapp?.alwaysReturnContent + ) { res.writeHead(200, { 'Content-type': 'application/javascript; charset=UTF-8', 'Content-Length': Buffer.byteLength(s), @@ -589,22 +595,24 @@ WebAppInternals.staticFilesMiddleware = async function ( } else { const status = req.method === 'OPTIONS' ? 200 : 405; res.writeHead(status, { - 'Allow': 'OPTIONS, GET, HEAD', + Allow: 'OPTIONS, GET, HEAD', 'Content-Length': '0', }); res.end(); } }; - if (_.has(additionalStaticJs, pathname) && - ! WebAppInternals.inlineScriptsAllowed()) { + if ( + _.has(additionalStaticJs, pathname) && + !WebAppInternals.inlineScriptsAllowed() + ) { serveStaticJs(additionalStaticJs[pathname]); return; } const { arch, path } = WebApp.categorizeRequest(req); - if (! hasOwn.call(WebApp.clientPrograms, arch)) { + if (!hasOwn.call(WebApp.clientPrograms, arch)) { // We could come here in case we run with some architectures excluded next(); return; @@ -615,24 +623,32 @@ WebAppInternals.staticFilesMiddleware = async function ( const program = WebApp.clientPrograms[arch]; await program.paused; - if (path === "/meteor_runtime_config.js" && - ! WebAppInternals.inlineScriptsAllowed()) { - serveStaticJs(`__meteor_runtime_config__ = ${program.meteorRuntimeConfig};`); + if ( + path === '/meteor_runtime_config.js' && + !WebAppInternals.inlineScriptsAllowed() + ) { + serveStaticJs( + `__meteor_runtime_config__ = ${program.meteorRuntimeConfig};` + ); return; } const info = getStaticFileInfo(staticFilesByArch, pathname, path, arch); - if (! info) { + if (!info) { next(); return; } // "send" will handle HEAD & GET requests - if (req.method !== 'HEAD' && req.method !== 'GET') { + if ( + req.method !== 'HEAD' && + req.method !== 'GET' && + !Meteor.settings.packages?.webapp?.alwaysReturnContent + ) { const status = req.method === 'OPTIONS' ? 200 : 405; res.writeHead(status, { - 'Allow': 'OPTIONS, GET, HEAD', + Allow: 'OPTIONS, GET, HEAD', 'Content-Length': '0', - }) + }); res.end(); return; } @@ -644,16 +660,14 @@ WebAppInternals.staticFilesMiddleware = async function ( // Cacheable files are files that should never change. Typically // named by their hash (eg meteor bundled js and css files). // We cache them ~forever (1yr). - const maxAge = info.cacheable - ? 1000 * 60 * 60 * 24 * 365 - : 0; + const maxAge = info.cacheable ? 1000 * 60 * 60 * 24 * 365 : 0; if (info.cacheable) { // Since we use req.headers["user-agent"] to determine whether the // client should receive modern or legacy resources, tell the client // to invalidate cached resources when/if its user agent string // changes in the future. - res.setHeader("Vary", "User-Agent"); + res.setHeader('Vary', 'User-Agent'); } // Set the X-SourceMap header, which current Chrome, FireFox, and Safari @@ -663,18 +677,18 @@ WebAppInternals.staticFilesMiddleware = async function ( // You may also need to enable source maps in Chrome: open dev tools, click // the gear in the bottom right corner, and select "enable source maps". if (info.sourceMapUrl) { - res.setHeader('X-SourceMap', - __meteor_runtime_config__.ROOT_URL_PATH_PREFIX + - info.sourceMapUrl); + res.setHeader( + 'X-SourceMap', + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX + info.sourceMapUrl + ); } - if (info.type === "js" || - info.type === "dynamic js") { - res.setHeader("Content-Type", "application/javascript; charset=UTF-8"); - } else if (info.type === "css") { - res.setHeader("Content-Type", "text/css; charset=UTF-8"); - } else if (info.type === "json") { - res.setHeader("Content-Type", "application/json; charset=UTF-8"); + if (info.type === 'js' || info.type === 'dynamic js') { + res.setHeader('Content-Type', 'application/javascript; charset=UTF-8'); + } else if (info.type === 'css') { + res.setHeader('Content-Type', 'text/css; charset=UTF-8'); + } else if (info.type === 'json') { + res.setHeader('Content-Type', 'application/json; charset=UTF-8'); } if (info.hash) { @@ -689,21 +703,24 @@ WebAppInternals.staticFilesMiddleware = async function ( send(req, info.absolutePath, { maxage: maxAge, dotfiles: 'allow', // if we specified a dotfile in the manifest, serve it - lastModified: false // don't set last-modified based on the file date - }).on('error', function (err) { - Log.error("Error serving static file " + err); - res.writeHead(500); - res.end(); - }).on('directory', function () { - Log.error("Unexpected directory " + info.absolutePath); - res.writeHead(500); - res.end(); - }).pipe(res); + lastModified: false, // don't set last-modified based on the file date + }) + .on('error', function(err) { + Log.error('Error serving static file ' + err); + res.writeHead(500); + res.end(); + }) + .on('directory', function() { + Log.error('Unexpected directory ' + info.absolutePath); + res.writeHead(500); + res.end(); + }) + .pipe(res); } }; function getStaticFileInfo(staticFilesByArch, originalPath, path, arch) { - if (! hasOwn.call(WebApp.clientPrograms, arch)) { + if (!hasOwn.call(WebApp.clientPrograms, arch)) { return null; } @@ -724,7 +741,7 @@ function getStaticFileInfo(staticFilesByArch, originalPath, path, arch) { info = staticFiles[path]; // Sometimes we register a lazy function instead of actual data in // the staticFiles manifest. - if (typeof info === "function") { + if (typeof info === 'function') { info = staticFiles[path] = info(); } return info; @@ -737,8 +754,7 @@ function getStaticFileInfo(staticFilesByArch, originalPath, path, arch) { } // If categorizeRequest returned an alternate path, try that instead. - if (path !== originalPath && - hasOwn.call(staticFiles, path)) { + if (path !== originalPath && hasOwn.call(staticFiles, path)) { return finalize(path); } }); @@ -758,15 +774,15 @@ WebAppInternals.parsePort = port => { parsedPort = port; } return parsedPort; -} +}; -import { onMessage } from "meteor/inter-process-messaging"; +import { onMessage } from 'meteor/inter-process-messaging'; -onMessage("webapp-pause-client", async ({ arch }) => { +onMessage('webapp-pause-client', async ({ arch }) => { WebAppInternals.pauseClient(arch); }); -onMessage("webapp-reload-client", async ({ arch }) => { +onMessage('webapp-reload-client', async ({ arch }) => { WebAppInternals.generateClientProgram(arch); }); @@ -774,17 +790,17 @@ function runWebAppServer() { var shuttingDown = false; var syncQueue = new Meteor._SynchronousQueue(); - var getItemPathname = function (itemUrl) { + var getItemPathname = function(itemUrl) { return decodeURIComponent(parseUrl(itemUrl).pathname); }; - WebAppInternals.reloadClientPrograms = function () { + WebAppInternals.reloadClientPrograms = function() { syncQueue.runTask(function() { const staticFilesByArch = Object.create(null); const { configJson } = __meteor_bootstrap__; - const clientArchs = configJson.clientArchs || - Object.keys(configJson.clientPaths); + const clientArchs = + configJson.clientArchs || Object.keys(configJson.clientPaths); try { clientArchs.forEach(arch => { @@ -792,7 +808,7 @@ function runWebAppServer() { }); WebAppInternals.staticFilesByArch = staticFilesByArch; } catch (e) { - Log.error("Error reloading the client program: " + e.stack); + Log.error('Error reloading the client program: ' + e.stack); process.exit(1); } }); @@ -800,15 +816,15 @@ function runWebAppServer() { // Pause any incoming requests and make them wait for the program to be // unpaused the next time generateClientProgram(arch) is called. - WebAppInternals.pauseClient = function (arch) { + WebAppInternals.pauseClient = function(arch) { syncQueue.runTask(() => { const program = WebApp.clientPrograms[arch]; const { unpause } = program; program.paused = new Promise(resolve => { - if (typeof unpause === "function") { + if (typeof unpause === 'function') { // If there happens to be an existing program.unpause function, // compose it with the resolve function. - program.unpause = function () { + program.unpause = function() { unpause(); resolve(); }; @@ -819,52 +835,54 @@ function runWebAppServer() { }); }; - WebAppInternals.generateClientProgram = function (arch) { + WebAppInternals.generateClientProgram = function(arch) { syncQueue.runTask(() => generateClientProgram(arch)); }; function generateClientProgram( arch, - staticFilesByArch = WebAppInternals.staticFilesByArch, + staticFilesByArch = WebAppInternals.staticFilesByArch ) { const clientDir = pathJoin( pathDirname(__meteor_bootstrap__.serverDir), - arch, + arch ); // read the control for the client we'll be serving up - const programJsonPath = pathJoin(clientDir, "program.json"); + const programJsonPath = pathJoin(clientDir, 'program.json'); let programJson; try { programJson = JSON.parse(readFileSync(programJsonPath)); } catch (e) { - if (e.code === "ENOENT") return; + if (e.code === 'ENOENT') return; throw e; } - if (programJson.format !== "web-program-pre1") { - throw new Error("Unsupported format for client assets: " + - JSON.stringify(programJson.format)); + if (programJson.format !== 'web-program-pre1') { + throw new Error( + 'Unsupported format for client assets: ' + + JSON.stringify(programJson.format) + ); } - if (! programJsonPath || ! clientDir || ! programJson) { - throw new Error("Client config file not parsed."); + if (!programJsonPath || !clientDir || !programJson) { + throw new Error('Client config file not parsed.'); } archPath[arch] = clientDir; - const staticFiles = staticFilesByArch[arch] = Object.create(null); + const staticFiles = (staticFilesByArch[arch] = Object.create(null)); const { manifest } = programJson; manifest.forEach(item => { - if (item.url && item.where === "client") { + if (item.url && item.where === 'client') { staticFiles[getItemPathname(item.url)] = { absolutePath: pathJoin(clientDir, item.path), cacheable: item.cacheable, hash: item.hash, // Link from source to its map sourceMapUrl: item.sourceMapUrl, - type: item.type + type: item.type, }; if (item.sourceMap) { @@ -872,7 +890,7 @@ function runWebAppServer() { // all source maps are cacheable. staticFiles[getItemPathname(item.sourceMapUrl)] = { absolutePath: pathJoin(clientDir, item.sourceMap), - cacheable: true + cacheable: true, }; } } @@ -884,8 +902,8 @@ function runWebAppServer() { }; const oldProgram = WebApp.clientPrograms[arch]; - const newProgram = WebApp.clientPrograms[arch] = { - format: "web-program-pre1", + const newProgram = (WebApp.clientPrograms[arch] = { + format: 'web-program-pre1', manifest: manifest, // Use arrow functions so that these versions can be lazily // calculated later, and so that they will not be included in the @@ -894,36 +912,45 @@ function runWebAppServer() { // Note: these version calculations must be kept in agreement with // CordovaBuilder#appendVersion in tools/cordova/builder.js, or hot // code push will reload Cordova apps unnecessarily. - version: () => WebAppHashing.calculateClientHash( - manifest, null, configOverrides), - versionRefreshable: () => WebAppHashing.calculateClientHash( - manifest, type => type === "css", configOverrides), - versionNonRefreshable: () => WebAppHashing.calculateClientHash( - manifest, (type, replaceable) => type !== "css" && !replaceable, configOverrides), - versionReplaceable: () => WebAppHashing.calculateClientHash( - manifest, (_type, replaceable) => { - if (Meteor.isProduction && replaceable) { - throw new Error('Unexpected replaceable file in production'); - } + version: () => + WebAppHashing.calculateClientHash(manifest, null, configOverrides), + versionRefreshable: () => + WebAppHashing.calculateClientHash( + manifest, + type => type === 'css', + configOverrides + ), + versionNonRefreshable: () => + WebAppHashing.calculateClientHash( + manifest, + (type, replaceable) => type !== 'css' && !replaceable, + configOverrides + ), + versionReplaceable: () => + WebAppHashing.calculateClientHash( + manifest, + (_type, replaceable) => { + if (Meteor.isProduction && replaceable) { + throw new Error('Unexpected replaceable file in production'); + } - return replaceable - }, - configOverrides - ), + return replaceable; + }, + configOverrides + ), cordovaCompatibilityVersions: programJson.cordovaCompatibilityVersions, PUBLIC_SETTINGS, hmrVersion: programJson.hmrVersion, - }; + }); // Expose program details as a string reachable via the following URL. - const manifestUrlPrefix = "/__" + arch.replace(/^web\./, ""); - const manifestUrl = manifestUrlPrefix + getItemPathname("/manifest.json"); + const manifestUrlPrefix = '/__' + arch.replace(/^web\./, ''); + const manifestUrl = manifestUrlPrefix + getItemPathname('/manifest.json'); staticFiles[manifestUrl] = () => { if (Package.autoupdate) { const { - AUTOUPDATE_VERSION = - Package.autoupdate.Autoupdate.autoupdateVersion + AUTOUPDATE_VERSION = Package.autoupdate.Autoupdate.autoupdateVersion, } = process.env; if (AUTOUPDATE_VERSION) { @@ -931,7 +958,7 @@ function runWebAppServer() { } } - if (typeof newProgram.version === "function") { + if (typeof newProgram.version === 'function') { newProgram.version = newProgram.version(); } @@ -939,7 +966,7 @@ function runWebAppServer() { content: JSON.stringify(newProgram), cacheable: false, hash: newProgram.version, - type: "json" + type: 'json', }; }; @@ -947,11 +974,10 @@ function runWebAppServer() { // If there are any requests waiting on oldProgram.paused, let them // continue now (using the new program). - if (oldProgram && - oldProgram.paused) { + if (oldProgram && oldProgram.paused) { oldProgram.unpause(); } - }; + } const defaultOptionsForArch = { 'web.cordova': { @@ -966,46 +992,45 @@ function runWebAppServer() { // redirects. (Plus it's undesirable to have clients // connecting to http://example.meteor.com when force-ssl is // in use.) - DDP_DEFAULT_CONNECTION_URL: process.env.MOBILE_DDP_URL || - Meteor.absoluteUrl(), - ROOT_URL: process.env.MOBILE_ROOT_URL || - Meteor.absoluteUrl() - } + DDP_DEFAULT_CONNECTION_URL: + process.env.MOBILE_DDP_URL || Meteor.absoluteUrl(), + ROOT_URL: process.env.MOBILE_ROOT_URL || Meteor.absoluteUrl(), + }, }, - "web.browser": { + 'web.browser': { runtimeConfigOverrides: { isModern: true, - } + }, }, - "web.browser.legacy": { + 'web.browser.legacy': { runtimeConfigOverrides: { isModern: false, - } + }, }, }; - WebAppInternals.generateBoilerplate = function () { + WebAppInternals.generateBoilerplate = function() { // This boilerplate will be served to the mobile devices when used with // Meteor/Cordova for the Hot-Code Push and since the file will be served by // the device's server, it is important to set the DDP url to the actual // Meteor server accepting DDP connections and not the device's file server. syncQueue.runTask(function() { - Object.keys(WebApp.clientPrograms) - .forEach(generateBoilerplateForArch); + Object.keys(WebApp.clientPrograms).forEach(generateBoilerplateForArch); }); }; function generateBoilerplateForArch(arch) { const program = WebApp.clientPrograms[arch]; const additionalOptions = defaultOptionsForArch[arch] || {}; - const { baseData } = boilerplateByArch[arch] = - WebAppInternals.generateBoilerplateInstance( - arch, - program.manifest, - additionalOptions, - ); + const { baseData } = (boilerplateByArch[ + arch + ] = WebAppInternals.generateBoilerplateInstance( + arch, + program.manifest, + additionalOptions + )); // We need the runtime config with overrides for meteor_runtime_config.js: program.meteorRuntimeConfig = JSON.stringify({ ...__meteor_runtime_config__, @@ -1027,7 +1052,7 @@ function runWebAppServer() { app.use(rawConnectHandlers); // Auto-compress any json, javascript, or text. - app.use(compress({filter: shouldCompress})); + app.use(compress({ filter: shouldCompress })); // parse cookies into an object app.use(cookieParser()); @@ -1040,7 +1065,7 @@ function runWebAppServer() { return; } res.writeHead(400); - res.write("Not a proxy"); + res.write('Not a proxy'); res.end(); }); @@ -1049,24 +1074,26 @@ function runWebAppServer() { // // Do this before the next middleware destroys req.url if a path prefix // is set to close #10111. - app.use(function (request, response, next) { + app.use(function(request, response, next) { request.query = qs.parse(parseUrl(request.url).query); next(); }); function getPathParts(path) { - const parts = path.split("/"); - while (parts[0] === "") parts.shift(); + const parts = path.split('/'); + while (parts[0] === '') parts.shift(); return parts; } function isPrefixOf(prefix, array) { - return prefix.length <= array.length && - prefix.every((part, i) => part === array[i]); + return ( + prefix.length <= array.length && + prefix.every((part, i) => part === array[i]) + ); } // Strip off the path prefix, if it exists. - app.use(function (request, response, next) { + app.use(function(request, response, next) { const pathPrefix = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX; const { pathname, search } = parseUrl(request.url); @@ -1075,7 +1102,7 @@ function runWebAppServer() { const prefixParts = getPathParts(pathPrefix); const pathParts = getPathParts(pathname); if (isPrefixOf(prefixParts, pathParts)) { - request.url = "/" + pathParts.slice(prefixParts.length).join("/"); + request.url = '/' + pathParts.slice(prefixParts.length).join('/'); if (search) { request.url += search; } @@ -1083,14 +1110,13 @@ function runWebAppServer() { } } - if (pathname === "/favicon.ico" || - pathname === "/robots.txt") { + if (pathname === '/favicon.ico' || pathname === '/robots.txt') { return next(); } if (pathPrefix) { response.writeHead(404); - response.write("Unknown path"); + response.write('Unknown path'); response.end(); return; } @@ -1100,17 +1126,18 @@ function runWebAppServer() { // Serve static files from the manifest. // This is inspired by the 'static' middleware. - app.use(function (req, res, next) { + app.use(function(req, res, next) { WebAppInternals.staticFilesMiddleware( WebAppInternals.staticFilesByArch, - req, res, next + req, + res, + next ); }); // Core Meteor packages like dynamic-import can add handlers before // other handlers added by package and application code. - app.use(WebAppInternals.meteorInternalHandlers = connect()); - + app.use((WebAppInternals.meteorInternalHandlers = connect())); /** * @name connectHandlersCallback(req, res, next) @@ -1130,7 +1157,7 @@ function runWebAppServer() { * @param {Function} next * Calling this function will pass on the handling of * this request to the next relevant handler. - * + * */ /** @@ -1141,13 +1168,13 @@ function runWebAppServer() { * @param {String} [path] * This handler will only be called on paths that match * this string. The match has to border on a `/` or a `.`. - * + * * For example, `/hello` will match `/hello/world` and * `/hello.world`, but not `/hello_world`. * @param {connectHandlersCallback} handler * A handler function that will be called on HTTP requests. * See `connectHandlersCallback` - * + * */ // Packages and apps can add handlers to this via WebApp.connectHandlers. // They are inserted before our default handler. @@ -1158,29 +1185,32 @@ function runWebAppServer() { // connect knows it is an error handler because it has 4 arguments instead of // 3. go figure. (It is not smart enough to find such a thing if it's hidden // inside packageAndAppHandlers.) - app.use(function (err, req, res, next) { + app.use(function(err, req, res, next) { if (!err || !suppressConnectErrors || !req.headers['x-suppress-error']) { next(err); return; } res.writeHead(err.status, { 'Content-Type': 'text/plain' }); - res.end("An error message"); + res.end('An error message'); }); - app.use(async function (req, res, next) { - if (! appUrl(req.url)) { + app.use(async function(req, res, next) { + if (!appUrl(req.url)) { return next(); - - } else if (req.method !== 'HEAD' && req.method !== 'GET') { + } else if ( + req.method !== 'HEAD' && + req.method !== 'GET' && + !Meteor.settings.packages?.webapp?.alwaysReturnContent + ) { const status = req.method === 'OPTIONS' ? 200 : 405; res.writeHead(status, { - 'Allow': 'OPTIONS, GET, HEAD', + Allow: 'OPTIONS, GET, HEAD', 'Content-Length': '0', - }) + }); res.end(); } else { var headers = { - 'Content-Type': 'text/html; charset=utf-8' + 'Content-Type': 'text/html; charset=utf-8', }; if (shuttingDown) { @@ -1200,7 +1230,7 @@ function runWebAppServer() { headers['Content-Type'] = 'text/css; charset=utf-8'; headers['Cache-Control'] = 'no-cache'; res.writeHead(200, headers); - res.write(".meteor-css-not-found-error { width: 0px;}"); + res.write('.meteor-css-not-found-error { width: 0px;}'); res.end(); return; } @@ -1212,7 +1242,7 @@ function runWebAppServer() { // already!) headers['Cache-Control'] = 'no-cache'; res.writeHead(404, headers); - res.end("404 Not Found"); + res.end('404 Not Found'); return; } @@ -1223,14 +1253,14 @@ function runWebAppServer() { // So similar to the situation above, we serve an uncached 404. headers['Cache-Control'] = 'no-cache'; res.writeHead(404, headers); - res.end("404 Not Found"); + res.end('404 Not Found'); return; } const { arch } = request; - assert.strictEqual(typeof arch, "string", { arch }); + assert.strictEqual(typeof arch, 'string', { arch }); - if (! hasOwn.call(WebApp.clientPrograms, arch)) { + if (!hasOwn.call(WebApp.clientPrograms, arch)) { // We could come here in case we run with some architectures excluded headers['Cache-Control'] = 'no-cache'; res.writeHead(404, headers); @@ -1238,7 +1268,7 @@ function runWebAppServer() { res.end(`No client program found for the ${arch} architecture.`); } else { // Safety net, but this branch should not be possible. - res.end("404 Not Found"); + res.end('404 Not Found'); } return; } @@ -1247,41 +1277,37 @@ function runWebAppServer() { // Promise that will be resolved when the program is unpaused. await WebApp.clientPrograms[arch].paused; - return getBoilerplateAsync(request, arch).then(({ - stream, - statusCode, - headers: newHeaders, - }) => { - if (!statusCode) { - statusCode = res.statusCode ? res.statusCode : 200; - } + return getBoilerplateAsync(request, arch) + .then(({ stream, statusCode, headers: newHeaders }) => { + if (!statusCode) { + statusCode = res.statusCode ? res.statusCode : 200; + } - if (newHeaders) { - Object.assign(headers, newHeaders); - } + if (newHeaders) { + Object.assign(headers, newHeaders); + } - res.writeHead(statusCode, headers); + res.writeHead(statusCode, headers); - stream.pipe(res, { - // End the response when the stream ends. - end: true, + stream.pipe(res, { + // End the response when the stream ends. + end: true, + }); + }) + .catch(error => { + Log.error('Error running template: ' + error.stack); + res.writeHead(500, headers); + res.end(); }); - - }).catch(error => { - Log.error("Error running template: " + error.stack); - res.writeHead(500, headers); - res.end(); - }); } }); // Return 404 by default, if no other handlers serve this URL. - app.use(function (req, res) { + app.use(function(req, res) { res.writeHead(404); res.end(); }); - var httpServer = createServer(app); var onListeningCallbacks = []; @@ -1324,18 +1350,16 @@ function runWebAppServer() { httpServer: httpServer, connectApp: app, // For testing. - suppressConnectErrors: function () { + suppressConnectErrors: function() { suppressConnectErrors = true; }, - onListening: function (f) { - if (onListeningCallbacks) - onListeningCallbacks.push(f); - else - f(); + onListening: function(f) { + if (onListeningCallbacks) onListeningCallbacks.push(f); + else f(); }, // This can be overridden by users who want to modify how listening works // (eg, to run a proxy like Apollo Engine Proxy in front of the server). - startListening: function (httpServer, listenOptions, cb) { + startListening: function(httpServer, listenOptions, cb) { httpServer.listen(listenOptions, cb); }, }); @@ -1347,17 +1371,26 @@ function runWebAppServer() { WebAppInternals.generateBoilerplate(); const startHttpServer = listenOptions => { - WebApp.startListening(httpServer, listenOptions, Meteor.bindEnvironment(() => { - if (process.env.METEOR_PRINT_ON_LISTEN) { - console.log("LISTENING"); - } - const callbacks = onListeningCallbacks; - onListeningCallbacks = null; - callbacks.forEach(callback => { callback(); }); - }, e => { - console.error("Error listening:", e); - console.error(e && e.stack); - })); + WebApp.startListening( + httpServer, + listenOptions, + Meteor.bindEnvironment( + () => { + if (process.env.METEOR_PRINT_ON_LISTEN) { + console.log('LISTENING'); + } + const callbacks = onListeningCallbacks; + onListeningCallbacks = null; + callbacks.forEach(callback => { + callback(); + }); + }, + e => { + console.error('Error listening:', e); + console.error(e && e.stack); + } + ) + ); }; let localPort = process.env.PORT || 0; @@ -1365,28 +1398,30 @@ function runWebAppServer() { if (unixSocketPath) { if (cluster.isWorker) { - const workerName = cluster.worker.process.env.name || cluster.worker.id - unixSocketPath += "." + workerName + ".sock"; + const workerName = cluster.worker.process.env.name || cluster.worker.id; + unixSocketPath += '.' + workerName + '.sock'; } // Start the HTTP server using a socket file. removeExistingSocketFile(unixSocketPath); startHttpServer({ path: unixSocketPath }); - const unixSocketPermissions = (process.env.UNIX_SOCKET_PERMISSIONS || "").trim(); + const unixSocketPermissions = ( + process.env.UNIX_SOCKET_PERMISSIONS || '' + ).trim(); if (unixSocketPermissions) { if (/^[0-7]{3}$/.test(unixSocketPermissions)) { chmodSync(unixSocketPath, parseInt(unixSocketPermissions, 8)); } else { - throw new Error("Invalid UNIX_SOCKET_PERMISSIONS specified"); + throw new Error('Invalid UNIX_SOCKET_PERMISSIONS specified'); } } - const unixSocketGroup = (process.env.UNIX_SOCKET_GROUP || "").trim(); + const unixSocketGroup = (process.env.UNIX_SOCKET_GROUP || '').trim(); if (unixSocketGroup) { //whomst automatically handles both group names and numerical gids const unixSocketGroupInfo = whomst.sync.group(unixSocketGroup); if (unixSocketGroupInfo === null) { - throw new Error("Invalid UNIX_SOCKET_GROUP name specified"); + throw new Error('Invalid UNIX_SOCKET_GROUP name specified'); } chownSync(unixSocketPath, userInfo().uid, unixSocketGroupInfo.gid); } @@ -1397,28 +1432,28 @@ function runWebAppServer() { if (/\\\\?.+\\pipe\\?.+/.test(localPort)) { // Start the HTTP server using Windows Server style named pipe. startHttpServer({ path: localPort }); - } else if (typeof localPort === "number") { + } else if (typeof localPort === 'number') { // Start the HTTP server using TCP. startHttpServer({ port: localPort, - host: process.env.BIND_IP || "0.0.0.0" + host: process.env.BIND_IP || '0.0.0.0', }); } else { - throw new Error("Invalid PORT specified"); + throw new Error('Invalid PORT specified'); } } - return "DAEMON"; + return 'DAEMON'; }; } var inlineScriptsAllowed = true; -WebAppInternals.inlineScriptsAllowed = function () { +WebAppInternals.inlineScriptsAllowed = function() { return inlineScriptsAllowed; }; -WebAppInternals.setInlineScriptsAllowed = function (value) { +WebAppInternals.setInlineScriptsAllowed = function(value) { inlineScriptsAllowed = value; WebAppInternals.generateBoilerplate(); }; @@ -1430,16 +1465,15 @@ WebAppInternals.enableSubresourceIntegrity = function(use_credentials = false) { WebAppInternals.generateBoilerplate(); }; -WebAppInternals.setBundledJsCssUrlRewriteHook = function (hookFn) { +WebAppInternals.setBundledJsCssUrlRewriteHook = function(hookFn) { bundledJsCssUrlRewriteHook = hookFn; WebAppInternals.generateBoilerplate(); }; -WebAppInternals.setBundledJsCssPrefix = function (prefix) { +WebAppInternals.setBundledJsCssPrefix = function(prefix) { var self = this; - self.setBundledJsCssUrlRewriteHook( - function (url) { - return prefix + url; + self.setBundledJsCssUrlRewriteHook(function(url) { + return prefix + url; }); }; @@ -1448,8 +1482,8 @@ WebAppInternals.setBundledJsCssPrefix = function (prefix) { // unless inline scripts have been disabled, in which case it will be // served under `/`. var additionalStaticJs = {}; -WebAppInternals.addStaticJs = function (contents) { - additionalStaticJs["/" + sha1(contents) + ".js"] = contents; +WebAppInternals.addStaticJs = function(contents) { + additionalStaticJs['/' + sha1(contents) + '.js'] = contents; }; // Exported for tests diff --git a/tools/tests/apps/ecmascript-regression/.gitignore b/tools/tests/apps/ecmascript-regression/.gitignore new file mode 100644 index 0000000000..c2658d7d1b --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/tools/tests/apps/ecmascript-regression/.meteor/.finished-upgraders b/tools/tests/apps/ecmascript-regression/.meteor/.finished-upgraders new file mode 100644 index 0000000000..c07b6ff75a --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/.meteor/.finished-upgraders @@ -0,0 +1,19 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package +1.4.3-split-account-service-packages +1.5-add-dynamic-import-package +1.7-split-underscore-from-meteor-base +1.8.3-split-jquery-from-blaze diff --git a/tools/tests/apps/ecmascript-regression/.meteor/.gitignore b/tools/tests/apps/ecmascript-regression/.meteor/.gitignore new file mode 100644 index 0000000000..4083037423 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/tools/tests/apps/ecmascript-regression/.meteor/.id b/tools/tests/apps/ecmascript-regression/.meteor/.id new file mode 100644 index 0000000000..f8a221a824 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +y1s06jw2jowx.c256atzmooh5 diff --git a/tools/tests/apps/ecmascript-regression/.meteor/packages b/tools/tests/apps/ecmascript-regression/.meteor/packages new file mode 100644 index 0000000000..ab27ff6225 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/.meteor/packages @@ -0,0 +1,23 @@ +# Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +meteor-base@1.5.1 # Packages every Meteor app needs to have +mobile-experience@1.1.0 # Packages for a great mobile UX +mongo@1.13.0 # The database Meteor supports right now +reactive-var@1.0.11 # Reactive variable for tracker + +standard-minifier-css@1.7.4 # CSS minifier run for production mode +standard-minifier-js@2.7.0 # JS minifier run for production mode +es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers +ecmascript@0.15.3 # Enable ECMAScript2015+ syntax in app code +typescript@4.3.5 # Enable TypeScript syntax in .ts and .tsx modules +shell-server@0.5.0 # Server-side component of the `meteor shell` command +hot-module-replacement@0.3.0 # Update client in development without reloading the page + +autopublish@1.0.7 # Publish all data to the clients (for prototyping) +insecure@1.0.7 # Allow all DB writes from clients (for prototyping) +static-html@1.3.2 # Define static page content in .html files +react-meteor-data # React higher-order component for reactively tracking Meteor data diff --git a/tools/tests/apps/ecmascript-regression/.meteor/platforms b/tools/tests/apps/ecmascript-regression/.meteor/platforms new file mode 100644 index 0000000000..efeba1b50c --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/tools/tests/apps/ecmascript-regression/.meteor/release b/tools/tests/apps/ecmascript-regression/.meteor/release new file mode 100644 index 0000000000..e68993d453 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/.meteor/release @@ -0,0 +1 @@ +METEOR@2.4 diff --git a/tools/tests/apps/ecmascript-regression/.meteor/versions b/tools/tests/apps/ecmascript-regression/.meteor/versions new file mode 100644 index 0000000000..de86973195 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/.meteor/versions @@ -0,0 +1,78 @@ +allow-deny@1.1.0 +autopublish@1.0.7 +autoupdate@1.7.0 +babel-compiler@7.7.0 +babel-runtime@1.5.0 +base64@1.0.12 +binary-heap@1.0.11 +blaze-tools@1.1.2 +boilerplate-generator@1.7.1 +caching-compiler@1.2.2 +caching-html-compiler@1.2.1 +callback-hook@1.4.0 +check@1.3.1 +ddp@1.4.0 +ddp-client@2.5.0 +ddp-common@1.4.0 +ddp-server@2.5.0 +diff-sequence@1.1.1 +dynamic-import@0.7.1 +ecmascript@0.15.3 +ecmascript-runtime@0.8.0 +ecmascript-runtime-client@0.12.1 +ecmascript-runtime-server@0.11.0 +ejson@1.1.1 +es5-shim@4.8.0 +fetch@0.1.1 +geojson-utils@1.0.10 +hot-code-push@1.0.4 +hot-module-replacement@0.3.0 +html-tools@1.1.2 +htmljs@1.1.1 +http@1.0.10 +id-map@1.1.1 +insecure@1.0.7 +inter-process-messaging@0.1.1 +launch-screen@1.3.0 +logging@1.3.1 +meteor@1.10.0 +meteor-base@1.5.1 +meteortesting:browser-tests@1.3.4 +meteortesting:mocha@2.0.3 +meteortesting:mocha-core@8.0.1 +minifier-css@1.6.0 +minifier-js@2.7.1 +minimongo@1.7.0 +mobile-experience@1.1.0 +mobile-status-bar@1.1.0 +modern-browsers@0.1.7 +modules@0.17.0 +modules-runtime@0.12.0 +modules-runtime-hot@0.13.0 +mongo@1.13.0 +mongo-decimal@0.1.2 +mongo-dev-server@1.1.0 +mongo-id@1.0.8 +npm-mongo@3.9.1 +ordered-dict@1.1.0 +promise@0.12.0 +random@1.2.0 +react-fast-refresh@0.1.1 +react-meteor-data@2.3.3 +reactive-var@1.0.11 +reload@1.3.1 +retry@1.1.0 +routepolicy@1.1.1 +shell-server@0.5.0 +socket-stream-client@0.4.0 +spacebars-compiler@1.3.0 +standard-minifier-css@1.7.4 +standard-minifier-js@2.7.1 +static-html@1.3.2 +templating-tools@1.2.1 +tracker@1.2.0 +typescript@4.3.5 +underscore@1.0.10 +url@1.3.2 +webapp@1.12.0 +webapp-hashing@1.1.0 diff --git a/tools/tests/apps/ecmascript-regression/client/main.css b/tools/tests/apps/ecmascript-regression/client/main.css new file mode 100644 index 0000000000..7f354f0fa7 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/client/main.css @@ -0,0 +1,4 @@ +body { + padding: 10px; + font-family: sans-serif; +} diff --git a/tools/tests/apps/ecmascript-regression/client/main.html b/tools/tests/apps/ecmascript-regression/client/main.html new file mode 100644 index 0000000000..f7dff1c0d3 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/client/main.html @@ -0,0 +1,7 @@ + + escmascript-regression + + + +
+ diff --git a/tools/tests/apps/ecmascript-regression/client/main.jsx b/tools/tests/apps/ecmascript-regression/client/main.jsx new file mode 100644 index 0000000000..a42cee8ff3 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/client/main.jsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { Meteor } from 'meteor/meteor'; +import { render } from 'react-dom'; +import { App } from '/imports/ui/App'; + +Meteor.startup(() => { + render(, document.getElementById('react-target')); +}); diff --git a/tools/tests/apps/ecmascript-regression/imports/ui/App.jsx b/tools/tests/apps/ecmascript-regression/imports/ui/App.jsx new file mode 100644 index 0000000000..926399e85b --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/imports/ui/App.jsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { Hello } from './Hello.jsx'; + +export const App = () => ( +
+

Welcome to Meteor!

+ +
+); diff --git a/tools/tests/apps/ecmascript-regression/imports/ui/Hello.jsx b/tools/tests/apps/ecmascript-regression/imports/ui/Hello.jsx new file mode 100644 index 0000000000..15e0f185ac --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/imports/ui/Hello.jsx @@ -0,0 +1,16 @@ +import React, { useState } from 'react'; + +export const Hello = () => { + const [counter, setCounter] = useState(0); + + const increment = () => { + setCounter(counter + 1); + }; + + return ( +
+ +

You've pressed the button {counter} times.

+
+ ); +}; diff --git a/tools/tests/apps/ecmascript-regression/package-lock.json b/tools/tests/apps/ecmascript-regression/package-lock.json new file mode 100644 index 0000000000..d28c129bac --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/package-lock.json @@ -0,0 +1,1248 @@ +{ + "name": "escmascript-regression", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@babel/runtime": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@types/node": { + "version": "16.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", + "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", + "optional": true + }, + "@types/yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "devtools-protocol": { + "version": "0.0.901419", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.901419.tgz", + "integrity": "sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "meteor-node-stubs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.1.0.tgz", + "integrity": "sha512-YvMQb4zcfWA82wFdRVTyxq28GO+Us7GSdtP+bTtC/mV35yipKnWo4W4665O57AmLVFnz4zR+WIZW11b4sfCtJw==", + "requires": { + "assert": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^4.19.0", + "elliptic": "^6.5.4", + "events": "^3.3.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.0", + "process": "^0.11.10", + "punycode": "^2.1.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "0.0.1", + "url": "^0.11.0", + "util": "^0.12.4", + "vm-browserify": "^1.1.2" + }, + "dependencies": { + "asn1.js": { + "version": "5.4.1", + "bundled": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "assert": { + "version": "2.0.0", + "bundled": true, + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "available-typed-arrays": { + "version": "1.0.4", + "bundled": true + }, + "base64-js": { + "version": "1.5.1", + "bundled": true + }, + "bn.js": { + "version": "5.2.0", + "bundled": true + }, + "brorand": { + "version": "1.1.0", + "bundled": true + }, + "browserify-aes": { + "version": "1.2.0", + "bundled": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "bundled": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "bundled": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "bundled": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "bundled": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "bundled": true, + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "6.0.3", + "bundled": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "buffer-xor": { + "version": "1.0.3", + "bundled": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "bundled": true + }, + "call-bind": { + "version": "1.0.2", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "cipher-base": { + "version": "1.0.4", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "console-browserify": { + "version": "1.2.0", + "bundled": true + }, + "constants-browserify": { + "version": "1.0.0", + "bundled": true + }, + "create-ecdh": { + "version": "4.0.4", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "bundled": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "bundled": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "bundled": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "define-properties": { + "version": "1.1.3", + "bundled": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "des.js": { + "version": "1.0.1", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "diffie-hellman": { + "version": "5.0.3", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "domain-browser": { + "version": "4.19.0", + "bundled": true + }, + "elliptic": { + "version": "6.5.4", + "bundled": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "es-abstract": { + "version": "1.18.3", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "bundled": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-object-assign": { + "version": "1.1.0", + "bundled": true + }, + "events": { + "version": "3.3.0", + "bundled": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "bundled": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "foreach": { + "version": "2.0.5", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "get-intrinsic": { + "version": "1.1.1", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "bundled": true + }, + "has-symbols": { + "version": "1.0.2", + "bundled": true + }, + "hash-base": { + "version": "3.1.0", + "bundled": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "bundled": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "https-browserify": { + "version": "1.0.0", + "bundled": true + }, + "ieee754": { + "version": "1.2.1", + "bundled": true + }, + "inherits": { + "version": "2.0.4", + "bundled": true + }, + "is-arguments": { + "version": "1.1.0", + "bundled": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-bigint": { + "version": "1.0.2", + "bundled": true + }, + "is-boolean-object": { + "version": "1.1.1", + "bundled": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.3", + "bundled": true + }, + "is-date-object": { + "version": "1.0.4", + "bundled": true + }, + "is-generator-function": { + "version": "1.0.9", + "bundled": true + }, + "is-nan": { + "version": "1.3.2", + "bundled": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "bundled": true + }, + "is-number-object": { + "version": "1.0.5", + "bundled": true + }, + "is-regex": { + "version": "1.1.3", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.6", + "bundled": true + }, + "is-symbol": { + "version": "1.0.4", + "bundled": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.5", + "bundled": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + } + }, + "md5.js": { + "version": "1.3.5", + "bundled": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "bundled": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "bundled": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "bundled": true + }, + "object-inspect": { + "version": "1.10.3", + "bundled": true + }, + "object-is": { + "version": "1.1.5", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "bundled": true + }, + "object.assign": { + "version": "4.1.2", + "bundled": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "os-browserify": { + "version": "0.3.0", + "bundled": true + }, + "pako": { + "version": "1.0.11", + "bundled": true + }, + "parse-asn1": { + "version": "5.1.6", + "bundled": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "path-browserify": { + "version": "1.0.1", + "bundled": true + }, + "pbkdf2": { + "version": "3.1.2", + "bundled": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "process": { + "version": "0.11.10", + "bundled": true + }, + "public-encrypt": { + "version": "4.0.3", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "punycode": { + "version": "2.1.1", + "bundled": true + }, + "querystring": { + "version": "0.2.0", + "bundled": true + }, + "querystring-es3": { + "version": "0.2.1", + "bundled": true + }, + "randombytes": { + "version": "2.1.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "bundled": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "ripemd160": { + "version": "2.0.2", + "bundled": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "setimmediate": { + "version": "1.0.5", + "bundled": true + }, + "sha.js": { + "version": "2.4.11", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "stream-browserify": { + "version": "3.0.0", + "bundled": true, + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "stream-http": { + "version": "3.2.0", + "bundled": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "timers-browserify": { + "version": "2.0.12", + "bundled": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tty-browserify": { + "version": "0.0.1", + "bundled": true + }, + "unbox-primitive": { + "version": "1.0.1", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "url": { + "version": "0.11.0", + "bundled": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "bundled": true + } + } + }, + "util": { + "version": "0.12.4", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "vm-browserify": { + "version": "1.1.2", + "bundled": true + }, + "which-boxed-primitive": { + "version": "1.0.2", + "bundled": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.4", + "bundled": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, + "xtend": { + "version": "4.0.2", + "bundled": true + } + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, + "progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", + "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==" + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "puppeteer": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-10.4.0.tgz", + "integrity": "sha512-2cP8mBoqnu5gzAVpbZ0fRaobBWZM8GEUF4I1F6WbgHrKV/rz7SX8PG2wMymZgD0wo0UBlg2FBPNxlF/xlqW6+w==", + "requires": { + "debug": "4.3.1", + "devtools-protocol": "0.0.901419", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.0", + "node-fetch": "2.6.1", + "pkg-dir": "4.2.0", + "progress": "2.0.1", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "tar-fs": "2.0.0", + "unbzip2-stream": "1.3.3", + "ws": "7.4.6" + } + }, + "react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "tar-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", + "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", + "requires": { + "chownr": "^1.1.1", + "mkdirp": "^0.5.1", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "unbzip2-stream": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/tools/tests/apps/ecmascript-regression/package.json b/tools/tests/apps/ecmascript-regression/package.json new file mode 100644 index 0000000000..7d3b6a6aeb --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/package.json @@ -0,0 +1,23 @@ +{ + "name": "escmascript-regression", + "private": true, + "scripts": { + "start": "meteor run", + "test": "meteor test --driver-package meteortesting:mocha", + "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha --exclude-archs web.browser" + }, + "dependencies": { + "@babel/runtime": "^7.15.3", + "meteor-node-stubs": "^1.1.0", + "puppeteer": "^10.4.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "meteor": { + "mainModule": { + "client": "client/main.jsx", + "server": "server/main.js" + }, + "testModule": "tests/main.js" + } +} diff --git a/tools/tests/apps/ecmascript-regression/server/main.js b/tools/tests/apps/ecmascript-regression/server/main.js new file mode 100644 index 0000000000..38b1ad39bb --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/server/main.js @@ -0,0 +1 @@ +import { Meteor } from 'meteor/meteor'; diff --git a/tools/tests/apps/ecmascript-regression/tests/main.js b/tools/tests/apps/ecmascript-regression/tests/main.js new file mode 100644 index 0000000000..59219cb713 --- /dev/null +++ b/tools/tests/apps/ecmascript-regression/tests/main.js @@ -0,0 +1,27 @@ +import assert from 'assert'; + +describe('escmascript-regression', function() { + if (Meteor.isClient) { + it('NodeList spread', function() { + const div = document.createElement('div'); + document.body.appendChild(div); + + for (let i = 0; i < 5; i++) { + const child = document.createElement('div'); + child.innerText = `child ${i}`; + div.appendChild(child); + } + + try { + assert.strictEqual(div.childNodes?.length, 5); + const arr = [...div.childNodes]; + + arr.forEach((el, i) => { + assert.equal(el.innerText, `child ${i}`); + }); + } finally { + document.body.removeChild(div); + } + }); + } +}); diff --git a/tools/tests/modules.js b/tools/tests/modules.js index e121fcf5c4..02cc810d60 100644 --- a/tools/tests/modules.js +++ b/tools/tests/modules.js @@ -1,51 +1,54 @@ var selftest = require('../tool-testing/selftest.js'); var Sandbox = selftest.Sandbox; -var utils = require('../utils/utils.js'); import { getUrl } from '../utils/http-helpers.js'; -var MONGO_LISTENING = - { stdout: " [initandlisten] waiting for connections on port" }; +var MONGO_LISTENING = { + stdout: ' [initandlisten] waiting for connections on port', +}; function startRun(sandbox) { var run = sandbox.run(); - run.match("myapp"); - run.match("proxy"); + run.match('myapp'); + run.match('proxy'); run.tellMongo(MONGO_LISTENING); run.waitSecs(20); - run.match("MongoDB"); + run.match('MongoDB'); return run; -}; +} -selftest.define("modules - test app", function () { +selftest.define('modules - test app', function() { const s = new Sandbox(); // Make sure we use the right "env" section of .babelrc. - s.set("NODE_ENV", "development"); + s.set('NODE_ENV', 'development'); - // For meteortesting:mocha to work we must set test broswer driver + // For meteortesting:mocha to work we must set test browser driver // See https://github.com/meteortesting/meteor-mocha - s.set("TEST_BROWSER_DRIVER", "puppeteer"); + s.set('TEST_BROWSER_DRIVER', 'puppeteer'); - s.createApp("modules-test-app", "modules"); - s.cd("modules-test-app", function () { + s.createApp('modules-test-app', 'modules'); + s.cd('modules-test-app', function() { const run = s.run( - "test", "--once", "--full-app", - "--driver-package", "meteortesting:mocha" + 'test', + '--once', + '--full-app', + '--driver-package', + 'meteortesting:mocha' ); run.waitSecs(60); - run.match("App running at"); - run.match("SERVER FAILURES: 0"); - run.match("CLIENT FAILURES: 0"); + run.match('App running at'); + run.match('SERVER FAILURES: 0'); + run.match('CLIENT FAILURES: 0'); run.expectExit(0); }); }); -selftest.define("modules - unimported lazy files", function() { +selftest.define('modules - unimported lazy files', function() { const s = new Sandbox(); - s.createApp("myapp", "app-with-unimported-lazy-file"); - s.cd("myapp", function() { - const run = s.run("--once"); + s.createApp('myapp', 'app-with-unimported-lazy-file'); + s.cd('myapp', function() { + const run = s.run('--once'); run.waitSecs(30); run.expectExit(1); run.forbid("This file shouldn't be loaded"); @@ -55,43 +58,47 @@ selftest.define("modules - unimported lazy files", function() { // Checks that `import X from 'meteor/package'` will import (and re-export) the // mainModule if one exists, otherwise will simply export Package['package']. // Overlaps with compiler-plugin.js's "install-packages.js" code. -selftest.define("modules - import chain for packages", () => { +selftest.define('modules - import chain for packages', () => { const s = new Sandbox({ fakeMongo: true }); - s.createApp("myapp", "package-tests"); - s.cd("myapp"); + s.createApp('myapp', 'package-tests'); + s.cd('myapp'); - s.write(".meteor/packages", [ - "meteor-base", - "modules", - "with-add-files", - "with-main-module", - "" - ].join("\n")); + s.write( + '.meteor/packages', + ['meteor-base', 'modules', 'with-add-files', 'with-main-module', ''].join( + '\n' + ) + ); - s.write("main.js", [ - "var packageNameA = require('meteor/with-add-files').name;", - "var packageNameB = require('meteor/with-main-module').name;", - "", - "console.log('with-add-files: ' + packageNameA);", - "console.log('with-main-module: ' + packageNameB);", - "" - ].join("\n")); + s.write( + 'main.js', + [ + "var packageNameA = require('meteor/with-add-files').name;", + "var packageNameB = require('meteor/with-main-module').name;", + '', + "console.log('with-add-files: ' + packageNameA);", + "console.log('with-main-module: ' + packageNameB);", + '', + ].join('\n') + ); const run = startRun(s); run.waitSecs(30); // On the server, we just check that importing *works*, not *how* it works - run.match("with-add-files: with-add-files"); - run.match("with-main-module: with-main-module"); + run.match('with-add-files: with-add-files'); + run.match('with-main-module: with-main-module'); // On the client, we just check that install() is called correctly - checkModernAndLegacyUrls("/packages/modules.js", body => { + checkModernAndLegacyUrls('/packages/modules.js', body => { selftest.expectTrue(body.includes('\ninstall("with-add-files");')); selftest.expectTrue( - body.includes('\ninstall("with-main-module", ' + - '"meteor/with-main-module/with-main-module.js");') + body.includes( + '\ninstall("with-main-module", ' + + '"meteor/with-main-module/with-main-module.js");' + ) ); }); @@ -99,9 +106,9 @@ selftest.define("modules - import chain for packages", () => { }); function checkModernAndLegacyUrls(path, test) { - if (! path.startsWith("/")) { - path = "/" + path; + if (!path.startsWith('/')) { + path = '/' + path; } - test(getUrl("http://localhost:3000" + path)); - test(getUrl("http://localhost:3000/__browser.legacy" + path)); + test(getUrl('http://localhost:3000' + path)); + test(getUrl('http://localhost:3000/__browser.legacy' + path)); } diff --git a/tools/tests/regressions.js b/tools/tests/regressions.js new file mode 100644 index 0000000000..8fb620251f --- /dev/null +++ b/tools/tests/regressions.js @@ -0,0 +1,32 @@ +var selftest = require('../tool-testing/selftest.js'); +var Sandbox = selftest.Sandbox; + +selftest.define('regressions - web.browser.legacy', function() { + const s = new Sandbox(); + + // Make sure we use the right "env" section of .babelrc. + s.set('NODE_ENV', 'development'); + + // For meteortesting:mocha to work we must set test browser driver + // See https://github.com/meteortesting/meteor-mocha + s.set('TEST_BROWSER_DRIVER', 'puppeteer'); + + s.createApp('modules-test-app', 'ecmascript-regression'); + s.cd('modules-test-app', function() { + const run = s.run( + 'test', + '--once', + '--full-app', + '--driver-package', + 'meteortesting:mocha', + '--exclude-archs', + 'web.browser' + ); + + run.waitSecs(60); + run.match('App running at'); + run.match('SERVER FAILURES: 0'); + run.match('CLIENT FAILURES: 0'); + run.expectExit(0); + }); +});