diff --git a/Contributing.md b/Contributing.md index 8d739f2a89..d07f2d101a 100644 --- a/Contributing.md +++ b/Contributing.md @@ -158,7 +158,7 @@ designed to stand separately. At the same time, all the parts of core fit toget distinctive Meteor development experience. Core APIs should be consistent between the client and the server (not always workable; we don't have fibers on the client or a DOM on the server). We prefer synchronous APIs wherever possible: you can use `Meteor.wrapAsync` on the server to wrap -async APIs that take a callback. +async APIs that take a callback. Above all, we are concerned with two design requirements when evaluating any change to a core package: @@ -242,6 +242,17 @@ these guidelines: * Be sure your author field in git is properly filled out with your full name and email address so we can credit you. +#### Need help with your pull request? + +Meteor now has groups defined to cover different areas of the codebase. If you need help getting acceptance on a certain pull requests with an area of focus listed below, you can address the appropriate people in the pull request: + +* Meteor Data Team - This includes DDP, tracker, mongo, accounts, etc. You can mention @stubailo in the PR. +* Blaze - This includes Spacebars, Blaze, etc. You can mention @urigo or @yyx990803 in the PR. +* Build tools - This includes modules, build tool changes, etc. You can memtion @avital or @benjamn in the PR. +* Mobile integration - This includes Cordova, React Native, etc. You can mention @martijnwalraven in the PR. + +Including the people above is no guarantee that you will get a response, or ultimately that your pull request will be accepted. This section exists to give some minor guidance on internal Meteor Development Group team structures. + ## Running tests on Meteor core When you are working with code in the core Meteor packages, you will want to make sure you run the diff --git a/History.md b/History.md index 3a8f3519f7..d7006427b5 100644 --- a/History.md +++ b/History.md @@ -139,6 +139,10 @@ * Detect new Facebook user-agent in the `spiderable` package. #5516 +* `check` will now check all keys of an object, including inherited ones #6140 + +* Allow `git+` URL schemes for npm dependencies #844 + Patches contributed by GitHub users vereed, mitar, nathan-muir, robfallows, skishore, okland, Primigenus, zimme, welelay, rgoomar, bySabi, mbrookes, TomFreudenberg, TechPlexEngineer, zacharydenton, diff --git a/docs/client/search.js b/docs/client/search.js index 69918116f3..aadbbb4bb3 100644 --- a/docs/client/search.js +++ b/docs/client/search.js @@ -19,12 +19,10 @@ $(document).on("keydown", function (event) { } }); -// Open search with any non-special key -var keysToOpenSearch = /[A-Za-z0-9]/; $(document).on("keydown", function (event) { // Don't activate search for special keys or keys with modifiers - if (event.which && keysToOpenSearch.test(String.fromCharCode(event.which)) && - (! event.ctrlKey) && (! event.metaKey) && (! Session.get("searchOpen"))) { + if (event.which >= 48 && event.which <= 90 && (!event.ctrlKey) && + (!event.metaKey) && (!Session.get("searchOpen"))) { Session.set("searchOpen", true); Tracker.flush(); diff --git a/meteor b/meteor index 8285db5b7e..167ff1ca37 100755 --- a/meteor +++ b/meteor @@ -1,8 +1,9 @@ #!/usr/bin/env bash # Note: 0.5.17 used on branch origin/npm3 -# Note: 0.5.20 used on branch origin/cordova-improvements +# Note: 0.5.20 and 0.5.25 used on branch origin/cordova-improvements # Note: 0.5.21 used on branch release-1.2.2 +# Note: 0.5.23 used on branch release-1.3 BUNDLE_VERSION=0.5.24 # OS Check. Put here because here is where we download the precompiled diff --git a/packages/check/match.js b/packages/check/match.js index e12451bf32..5b21fcf880 100644 --- a/packages/check/match.js +++ b/packages/check/match.js @@ -325,7 +325,16 @@ var testSubtree = function (value, pattern) { requiredPatterns[key] = subPattern; }); - for (var keys = _.keys(value), i = 0, length = keys.length; i < length; i++) { + //XXX: replace with underscore's _.allKeys if Meteor updates underscore to 1.8+ (or lodash) + var allKeys = function(obj){ + var keys = []; + if (_.isObject(obj)){ + for (var key in obj) keys.push(key); + } + return keys; + } + + for (var keys = allKeys(value), i = 0, length = keys.length; i < length; i++) { var key = keys[i]; var subValue = value[key]; if (_.has(requiredPatterns, key)) { diff --git a/packages/check/match_test.js b/packages/check/match_test.js index 0328ca1572..5aed1dbd44 100644 --- a/packages/check/match_test.js +++ b/packages/check/match_test.js @@ -161,6 +161,14 @@ Tinytest.add("check - check", function (test) { fails(function () {}, Match.Integer); fails(new Date, Match.Integer); + + // Test objects that have a prototype + var parentObj = {foo:"bar"}; + var childObj = Object.assign(Object.create(parentObj),{bar:"foo"}); + matches(childObj,{foo:String,bar:String}); + fails(childObj,{bar:String}); + + // Test that "arguments" is treated like an array. var argumentsMatches = function () { matches(arguments, [Number]); diff --git a/packages/check/package.js b/packages/check/package.js index de83fe718b..cc0205130e 100644 --- a/packages/check/package.js +++ b/packages/check/package.js @@ -12,7 +12,7 @@ Package.onUse(function (api) { }); Package.onTest(function (api) { - api.use(['check', 'tinytest', 'underscore', 'ejson'], ['client', 'server']); + api.use(['check', 'tinytest', 'underscore', 'ejson', 'ecmascript'], ['client', 'server']); api.addFiles('match_test.js', ['client', 'server']); }); diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index 0b9decedd6..e09b62cbd0 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -323,7 +323,7 @@ var staticFiles; // Serve static files from the manifest or added with // `addStaticJs`. Exported for tests. WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) { - if ('GET' != req.method && 'HEAD' != req.method) { + if ('GET' != req.method && 'HEAD' != req.method && 'OPTIONS' != req.method) { next(); return; } @@ -501,9 +501,9 @@ var runWebAppServer = function () { // Serve the program as a string at /foo//manifest.json // XXX change manifest.json -> program.json - staticFiles[path.join(urlPrefix, getItemPathname('/manifest.json'))] = { + staticFiles[urlPrefix + getItemPathname('/manifest.json')] = { content: JSON.stringify(program), - cacheable: true, + cacheable: false, hash: program.version, type: "json" }; @@ -649,81 +649,83 @@ var runWebAppServer = function () { }); app.use(function (req, res, next) { - if (! appUrl(req.url)) - return next(); + Fiber(function () { + if (!appUrl(req.url)) + return next(); - var headers = { - 'Content-Type': 'text/html; charset=utf-8' - }; - if (shuttingDown) - headers['Connection'] = 'Close'; + var headers = { + 'Content-Type': 'text/html; charset=utf-8' + }; + if (shuttingDown) + headers['Connection'] = 'Close'; - var request = WebApp.categorizeRequest(req); + var request = WebApp.categorizeRequest(req); - if (request.url.query && request.url.query['meteor_css_resource']) { - // In this case, we're requesting a CSS resource in the meteor-specific - // way, but we don't have it. Serve a static css file that indicates that - // we didn't have it, so we can detect that and refresh. Make sure - // that any proxies or CDNs don't cache this error! (Normally proxies - // or CDNs are smart enough not to cache error pages, but in order to - // make this hack work, we need to return the CSS file as a 200, which - // would otherwise be cached.) - 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;}"); + if (request.url.query && request.url.query['meteor_css_resource']) { + // In this case, we're requesting a CSS resource in the meteor-specific + // way, but we don't have it. Serve a static css file that indicates that + // we didn't have it, so we can detect that and refresh. Make sure + // that any proxies or CDNs don't cache this error! (Normally proxies + // or CDNs are smart enough not to cache error pages, but in order to + // make this hack work, we need to return the CSS file as a 200, which + // would otherwise be cached.) + 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.end(); + return undefined; + } + + if (request.url.query && request.url.query['meteor_js_resource']) { + // Similarly, we're requesting a JS resource that we don't have. + // Serve an uncached 404. (We can't use the same hack we use for CSS, + // because actually acting on that hack requires us to have the JS + // already!) + headers['Cache-Control'] = 'no-cache'; + res.writeHead(404, headers); + res.end("404 Not Found"); + return undefined; + } + + if (request.url.query && request.url.query['meteor_dont_serve_index']) { + // When downloading files during a Cordova hot code push, we need + // to detect if a file is not available instead of inadvertently + // downloading the default index page. + // 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"); + return undefined; + } + + // /packages/asdfsad ... /__cordova/dafsdf.js + var pathname = parseurl(req).pathname; + var archKey = pathname.split('/')[1]; + var archKeyCleaned = 'web.' + archKey.replace(/^__/, ''); + + if (!/^__/.test(archKey) || !_.has(archPath, archKeyCleaned)) { + archKey = WebApp.defaultArch; + } else { + archKey = archKeyCleaned; + } + + var boilerplate; + try { + boilerplate = getBoilerplate(request, archKey); + } catch (e) { + Log.error("Error running template: " + e.stack); + res.writeHead(500, headers); + res.end(); + return undefined; + } + + var statusCode = res.statusCode ? res.statusCode : 200; + res.writeHead(statusCode, headers); + res.write(boilerplate); res.end(); return undefined; - } - - if (request.url.query && request.url.query['meteor_js_resource']) { - // Similarly, we're requesting a JS resource that we don't have. - // Serve an uncached 404. (We can't use the same hack we use for CSS, - // because actually acting on that hack requires us to have the JS - // already!) - headers['Cache-Control'] = 'no-cache'; - res.writeHead(404, headers); - res.end("404 Not Found"); - return undefined; - } - - if (request.url.query && request.url.query['meteor_dont_serve_index']) { - // When downloading files during a Cordova hot code push, we need - // to detect if a file is not available instead of inadvertently - // downloading the default index page. - // 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"); - return undefined; - } - - // /packages/asdfsad ... /__cordova/dafsdf.js - var pathname = parseurl(req).pathname; - var archKey = pathname.split('/')[1]; - var archKeyCleaned = 'web.' + archKey.replace(/^__/, ''); - - if (! /^__/.test(archKey) || ! _.has(archPath, archKeyCleaned)) { - archKey = WebApp.defaultArch; - } else { - archKey = archKeyCleaned; - } - - var boilerplate; - try { - boilerplate = getBoilerplate(request, archKey); - } catch (e) { - Log.error("Error running template: " + e.stack); - res.writeHead(500, headers); - res.end(); - return undefined; - } - - var statusCode = res.statusCode ? res.statusCode : 200; - res.writeHead(statusCode, headers); - res.write(boilerplate); - res.end(); - return undefined; + }).run(); }); // Return 404 by default, if no other handlers serve this URL. diff --git a/tools/cli/commands-cordova.js b/tools/cli/commands-cordova.js index 27c6098c4f..07d3bf6632 100644 --- a/tools/cli/commands-cordova.js +++ b/tools/cli/commands-cordova.js @@ -43,7 +43,7 @@ main.registerCommand({ for (platform of platformsToAdd) { if (_.contains(installedPlatforms, platform)) { buildmessage.error(`${platform}: platform is already added`); - } else if (!_.contains(cordova.AVAILABLE_PLATFORMS, platform)) { + } else if (!_.contains(cordova.CORDOVA_PLATFORMS, platform)) { buildmessage.error(`${platform}: no such platform`); } } @@ -67,7 +67,9 @@ main.registerCommand({ for (platform of platformsToAdd) { Console.info(`${platform}: added platform`); - cordovaProject.checkPlatformRequirements(platform); + if (_.contains(cordovaPlatforms, platform)) { + cordovaProject.checkPlatformRequirements(platform); + } } }); }); @@ -142,10 +144,10 @@ main.registerCommand({ const platform = options.args[0]; - if (!_.contains(cordova.AVAILABLE_PLATFORMS, platform)) { + if (!_.contains(cordova.CORDOVA_PLATFORMS, platform)) { Console.warn(`Unknown platform: ${platform}`); Console.info(`Valid platforms are: \ -${cordova.AVAILABLE_PLATFORMS.join(', ')}`); +${cordova.CORDOVA_PLATFORMS.join(', ')}`); return 1; } diff --git a/tools/cordova/index.js b/tools/cordova/index.js index 649f5b733a..9f20c778d9 100644 --- a/tools/cordova/index.js +++ b/tools/cordova/index.js @@ -8,7 +8,7 @@ import { oldToNew as oldToNewPluginIds, newToOld as newToOldPluginIds } export const CORDOVA_ARCH = "web.cordova"; -export const AVAILABLE_PLATFORMS = ['ios', 'android']; +export const CORDOVA_PLATFORMS = ['ios', 'android']; const PLATFORM_TO_DISPLAY_NAME_MAP = { 'ios': 'iOS', @@ -28,7 +28,7 @@ export function displayNamesForPlatforms(platforms) { // Right now, the only other platforms are the default browser and server // platforms. export function filterPlatforms(platforms) { - return _.intersection(platforms, AVAILABLE_PLATFORMS); + return _.intersection(platforms, CORDOVA_PLATFORMS); } export function splitPluginsAndPackages(packages) { diff --git a/tools/cordova/project.js b/tools/cordova/project.js index 47e5382fc2..d1462af302 100644 --- a/tools/cordova/project.js +++ b/tools/cordova/project.js @@ -21,7 +21,7 @@ import cordova_util from 'cordova-lib/src/cordova/util.js'; import superspawn from 'cordova-lib/src/cordova/superspawn.js'; import PluginInfoProvider from 'cordova-lib/src/PluginInfoProvider.js'; -import { AVAILABLE_PLATFORMS, displayNameForPlatform, displayNamesForPlatforms, +import { CORDOVA_PLATFORMS, displayNameForPlatform, displayNamesForPlatforms, newPluginId, convertPluginVersions, convertToGitUrl, installationInstructionsUrlForPlatform } from './index.js'; import { CordovaBuilder } from './builder.js'; @@ -363,7 +363,7 @@ from Cordova project`, async () => { for (platform of installedPlatforms) { if (!_.contains(platforms, platform) && - _.contains(AVAILABLE_PLATFORMS, platform)) { + _.contains(CORDOVA_PLATFORMS, platform)) { this.removePlatform(platform); } }