Commit Graph

94 Commits

Author SHA1 Message Date
Timmy Willison
bcfdf9a356
Build: Fix pre release matching in compare size regex
Some checks failed
Browserstack / ${{ matrix.BROWSER }} (IE_9) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (Opera_latest) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (Safari_latest) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (Safari_latest-1) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_10) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_11) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_12) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_13) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_14) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_15) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_16) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_17) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_8) (push) Has been cancelled
Browserstack / ${{ matrix.BROWSER }} (__iOS_9) (push) Has been cancelled
Code scanning - action / CodeQL-Build (push) Has been cancelled
Filestash / Update Filestash (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Chrome, 20.x, test:amd) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Chrome, 20.x, test:no-deprecated) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Chrome, 20.x, test:selector-native) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Chrome, 20.x, test:slim) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Chrome/Firefox, 20.x, test:browser) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Firefox ESR (new), 20.x, test:firefox) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Firefox ESR (old), 20.x, test:firefox) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Node, 18.x, test:browserless) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Node, 20.x, lint) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Node, 20.x, test:browserless) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Node, 22.x, test:browserless) (push) Has been cancelled
Node / ${{ matrix.NPM_SCRIPT }} - ${{ matrix.NAME }} (${{ matrix.NODE_VERSION }}) (Node, 23.x, test:browserless) (push) Has been cancelled
Node / test:ie - IE (push) Has been cancelled
Node / test:safari - Safari (push) Has been cancelled
Closes gh-5584

(cherry picked from commit 041f6e347b)
2024-11-21 11:22:23 +01:00
Timmy Willison
2cf659189e Release: migrate release process to release-it
*Authors*
- Checking and updating authors has been migrated
  to a custom script in the repo

*Changelog*
- changelogplease is no longer maintained
- generate changelog in markdown for GitHub releases
- generate changelog in HTML for blog posts
- generate contributors list in HTML for blog posts

*dist*
- clone dist repo, copy files, and commit/push
- commit tag with dist files on main branch;
  remove dist files from main branch after release

*cdn*
- clone cdn repo, copy files, and commit/push
- create versioned and unversioned copies in cdn/
- generate md5 sums and archives for Google and MSFT

*build*
- implement reproducible builds and verify release builds
  * uses the last modified date for the latest commit
  * See https://reproducible-builds.org/
- the verify workflow also ensures all files were
  properly published to the CDN and npm

*docs*
- the new release workflow is documented at build/release/README.md

*verify*
- use the last modified date of the commit before the tag
- use versioned filenames when checking map files on the CDN
- skip factory and package.json files when verifying CDN

*misc*
- now that we don't need the jquery-release script and
  now that we no longer need to build on Node 10, we can
  use ESM in all files in the build folder
- limit certain workflows to the main repo (not forks)
- version has been set to the previously released version 3.7.1,
  as release-it expects
- release-it added the `preReleaseBase` option and we
  now always set it to `1` in the npm script. This is
  a noop for stable releases.
- include post-release script to be run manually after a release,
  with further steps that should be verified manually

Ref jquery/jquery-release#114
Closes gh-5522
2024-07-29 15:25:14 -04:00
Timmy Willison
fc864c83c8
Build: upgrade dependencies, including eslint 9.4.0 and uglify 3.7.7
- Sinon is already at the latest version that supports IE9.
- Upgraded uglify to 3.7.7, which is the latest that worked with IE9.
  I tried 3.9.4, which we are using in jquery-migrate, and 3.8.1,
  but there were failures in traversing ("Permission denied" errors).
- Upgraded eslint to version 9, which required some changes.
  Mainly, unused arguments in catch expressions error by default in 9+.
  The config now makes use of `caughtErrorsIgnorePattern`,
  which is set to `"^_"`, the same as unused function params.
- Ignored main branch dist files when switching branches.

Closes gh-5508
2024-06-15 09:10:59 -04:00
Timmy Willison
b56c6a415e Build: make compare size cache readable for manual edits
Ref gh-5441
2024-03-11 13:36:09 -04:00
Timmy Willison
fa3f5603d8 Build: fix size comparison for slim files when the branch is dirty
Ref gh-5441
2024-03-11 13:36:09 -04:00
Timmy Willison
79a19b412c Build: migrate more uses of fs.promises; use node: protocol
Ref gh-5441
2024-03-11 13:36:09 -04:00
Timmy Willison
79329f5015 Build: drop support for Node 10
Close gh-5437
2024-03-09 10:36:33 -05:00
Timmy Willison
ef434cd8d3
Tests: migrate testing infrastructure to minimal dependencies
This is a complete rework of our testing infrastructure. The main goal is to modernize and drop deprecated or undermaintained dependencies (specifically, grunt, karma, and testswarm). We've achieved that by limiting our dependency list to ones that are unlikely to drop support any time soon. The new dependency list includes:

- `qunit` (our trusty unit testing library)
- `selenium-webdriver` (for spinning up local browsers)
- `express` (for starting a test server and adding middleware)
  - express middleware includes uses of `body-parser` and `raw-body`
- `yargs` (for constructing a CLI with pretty help text)
- BrowserStack (for running each of our QUnit modules separately in all of our supported browsers)
  - `browserstack-local` (for opening a local tunnel. This is the same package still currently used in the new Browserstack SDK)
  - We are not using any other BrowserStack library. The newest BrowserStack SDK does not fit our needs (and isn't open source). Existing libraries, such as `node-browserstack` or `browserstack-runner`, either do not quite fit our needs, are under-maintained and out-of-date, or are not robust enough to meet all of our requirements. We instead call the [BrowserStack REST API](https://github.com/browserstack/api) directly.

**BrowserStack**
- automatically retries individual modules in case of test failure(s)
- automatically attempts to re-establish broken tunnels
- automatically refreshes the page in case a test run has stalled
- Browser workers are reused when running isolated modules in the same browser
- runs all browsers concurrently and uses as many sessions as are available under the BrowserStack plan. It will wait for available sessions if there are none.
- supports filtering the available list of browsers by browser name, browser version, device, OS, and OS version (see `npm run test:unit -- --list-browsers` for more info). It will retrieve the latest matching browser available if any of those parameters are not specified. Supports latest and latest-\d+ in place of browser version.
- cleans up after itself (closes the local tunnel, stops the test server, etc.)
- Requires `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY` environment variables.

**Selenium**
- supports running any local browser as long as the driver is installed, including support for headless mode in Chrome, FF, and Edge
- supports running `basic` tests on the latest [jsdom](https://github.com/jsdom/jsdom#readme), which can be seen in action in this PR (see `test:browserless`)
- Node tests will run as before in PRs and all non-dependabot branches, but now includes tests on real Safari in a GH actions macos image instead of playwright-webkit.
- can run multiple browsers and multiple modules concurrently

Other notes:
- Stale dependencies have been removed and all remaining dependencies have been upgraded with a few exceptions:
  - `sinon`: stopped supporting IE in version 10. But, `sinon` has been updated to 9.x.
  - `husky`: latest does not support Node 10 and runs on `npm install`. Needed for now until git builds are migrated to GitHub Actions.
  - `rollup`: latest does not support Node 10. Needed for now until git builds are migrated to GitHub Actions.
- BrowserStack tests are set to run on each `main` branch commit
- `debug` mode leaves Selenium browsers open whether they pass or fail and leaves browsers with test failures open on BrowserStack. The latter is to avoid leaving open too many sessions.
- This PR includes a workflow to dispatch BrowserStack runs on-demand
- The Node version used for most workflow tests has been upgraded to 20.x
- updated supportjQuery to 3.7.1

Run `npm run test:unit -- --help` for CLI documentation

Close gh-5427
2024-03-05 13:53:39 -05:00
Timmy Willison
ba6ba5a4c1
Release: use buildDefaultFiles directly and pass version (#5409)
- also add the ability to pass VERSION in env to test final builds
- adjust sha regex to account for lack of shas
- set the version on the dist package.json

Close gh-5408
2024-02-06 10:16:05 -05:00
Michał Gołębiowski-Owczarek
e84886aa37
Build: Update ESLint-related packages, fix linting errors (3.x version)
The main change is the new rule in `eslint-config-jquery`:
`template-curly-spacing`.

Closes gh-5348
Ref jquery/eslint-config-jquery#21
Ref gh-5347
2023-11-02 00:48:05 +01:00
Timmy Willison
ce52a5dbb0
Build: sort branches in compare_size; last run last
Close gh-5334
2023-09-21 17:47:18 -04:00
Timmy Willison
ec8802bafe
Build: migrate most grunt tasks off of grunt (3.x)
Close gh-5330

- lint
- npmcopy
- build, minify, and process for distribution.
- new custom build command using yargs
- compare size of minified/gzip built files
- pretest scripts, including qunit-fixture, babel transpilation, and npmcopy
- node smoke tests
- promises aplus tests
- new watch task using nodemon, which runs `npm run build:all` on `src` changes.

Also:

- upgraded husky and added the new lint command
- updated lint config to use new "flat" config format.
	See https://eslint.org/docs/latest/use/configure/configuration-files-new
- Temporarily disabled one lint rule until flat config is
	supported by eslint-plugin-import.
	See https://github.com/import-js/eslint-plugin-import/issues/2556
- committed package-lock.json
- updated all test scripts to use the new build
- added an express test server that uses middleware-mockserver
	this can be used to run tests without karma
- build-all-variants is now build:all
- run pretest script in jenkins

---------

Co-authored-by: Michał Gołębiowski-Owczarek <m.goleb@gmail.com>
2023-09-20 18:18:42 -04:00
Michał Gołębiowski-Owczarek
763ade6dda
Build: Generate the slim build on grunt & run compare_size on it
Summary of the changes:
* expand `node_smoke_tests` to test the full & slim builds
* run `compare_size` on all built minified files; don't run it anymore on
  unminified files where they don't provide lots of value

The main goal of this change is to make it easier to compare sizes of both the
full & slim builds between the `3.x-stable` & `main` branches.

Closes gh-5291
Ref gh-5255

(partially cherry-picked from commit 8be4c0e4f8)
2023-07-10 20:45:30 +02:00
Timmy Willison
37b04d5aba
Build: remove stale Insight package from custom builds
Close gh-5181
2022-12-20 20:53:36 +00:00
Michał Gołębiowski-Owczarek
6306ca4994
Selector: Inline Sizzle into the selector module: 3.x version (#5113)
This commit removes Sizzle from jQuery, inlining its code & removing obsolete
workarounds where applicable.

The Sizzle AUTHORS.txt file has been merged with the jQuery one - people are
sorted by their first contributions to either of the two repositories.

The main `selector` module can be disabled in favor of `selector-native`
via:

    grunt custom:-selector

For backwards compatibility, the legacy `sizzle` alias is also supported (it
will be dropped in jQuery `4.0.0`):

    grunt custom:-selector

Sizzle tests have been ported to jQuery ones. Ones that are not compatible
with the `selector-native` module are disabled if the regular selector module
is excluded.

Backwards compatibility is still kept for all `Sizzle` utils - they continue to be
available under `jQuery.find` - but the primary implementation is now attached
directly to jQuery.

Some selector utils shared by `selector` & `selector-native` have been
extracted & deduplicated. `jQuery.text` and `jQuery.isXMLDoc` have been
moved to the `core` module.

The commit reduces the gzipped jQuery size by 851 bytes compared to the
`3.x-stable` branch.

Closes gh-5113
Ref gh-4395
Ref gh-4406
2022-12-14 01:41:31 +01:00
Michał Gołębiowski-Owczarek
bc16512879
Tests: Exclude tests based on compilation flags, not API presence (3.x version)
Introduces a new test API, `includesModule`. The method returns whether
a particular module like "ajax" or "deprecated" is included in the current
jQuery build; it handles the slim build as well. The util was created so that
we don't treat presence of particular APIs to decide whether to run a test as
then if we accidentally remove an API, the tests would still not fail.

Closes gh-5071
Fixes gh-5069
Ref gh-5046

(partially cherry picked from commit fae5fee8b4)
2022-07-12 17:12:27 +02:00
Michał Gołębiowski-Owczarek
d525ae3416
Build:Tests: Fix custom build tests, verify on Travis; name Travis jobs
This commit fixes unit tests for the following builds:

1. The no-deprecated build: `custom:-deprecated`
2. The current slim build: `custom:-ajax,-effects`
3. The 4.0 (#4553) slim build: `custom:-ajax,-callbacks,-deferred,-effects`

It also adds separate Travis jobs for the no-deprecated & slim builds.

Apart from that, add intuitive names to Travis jobs. Otherwise it's hard to see
at a glance that a particular job is running on Firefox ESR, for example.

Ref gh-4577
Ref gh-4596
Closes gh-4600
2020-01-27 18:54:47 +01:00
Michał Gołębiowski-Owczarek
4cbdc745cc Build: Create a grunt custom:slim alias for the Slim build
Closes gh-4578

(cherry-picked from 9b9ed469b4)
2020-01-07 16:45:22 +01:00
Michał Gołębiowski-Owczarek
ac2da4e6b9 Build: Require strict mode in Node.js scripts via ESLint
So far, only browser-based JS files were required to be in strict mode (in the
function form). This commit adds such a requirement to Node.js scripts where
the global form is preferred. All Node.js scripts in sloppy mode were
converted to strict mode.

Closes gh-4499

(cherry picked from commit bbad821c39)
2019-10-09 00:24:17 +02:00
Michał Gołębiowski-Owczarek
d7e13f128a Build: ESLint: forbid unused function parameters
This commit requires all function parameters to be used, not just the last one.
In cases where that's not possible as we need to match an external API, there's
an escape hatch of prefixing an unused argument with `_`.

This change makes it easier to catch unused AMD dependencies and unused
parameters in internal functions the API of which we may change at will, among
other things.

Unused AMD dependencies have been removed as part of this commit.

Closes gh-4381

(cherry-picked from 438b1a3e8a)
2019-09-26 01:59:57 +02:00
Michał Gołębiowski-Owczarek
36b59c9661 Build: Fix the regex parsing AMD var-modules (#4389)
The previous regex caused the final jQuery binary to have syntax errors for
var-modules with names starting with "return". For example, the following module
wouldn't work when the file is named `returnTrue.js`:

```js
define( function() {
	"use strict";
	return function returnTrue() {
		return true;
	};
} );
```

Closes gh-4389

(cherry picked from commit 9ec09c3b4a)
2019-09-26 01:18:22 +02:00
Michał Gołębiowski-Owczarek
84b6a0beb1
Build: Remove manual QUnit fixture resetting
It was needed when QUnit 1.x one used but we've since upgraded to QUnit 2.x.

Closes gh-4312
Ref gh-4307
2019-03-11 17:25:48 +01:00
Michał Gołębiowski-Owczarek
ca9356ecce
Build: Make Promises/A+ tests use the dot reporter instead of the default
The default reporter is very verbose as it prints all the test names it
encounters. We already use the dot reporter for Karma tests.

Closes gh-4313
2019-03-11 16:06:17 +01:00
Michał Gołębiowski-Owczarek
9cb124ed00
Build: Update jsdom; migrate a test with Symbol polyfill to an iframe test
So far, we've been testing that jQuery element iteration works with polyfilled
Symbol & transpiled for-of via a Node test with jsdom with the Symbol global
removed. Unfortunately, jsdom now requires Symbol to be present for its internal
functionality so such a test is no longer possible. Instead, it's been migrated
to an iframe test with transpiled JavaScript.

This PR also enables us to use ECMAScript 2017 or newer in Node.js code.

Closes gh-4305
2019-03-04 18:30:51 +01:00
Dave Methvin
6c38ebbd47 Build: Remove CRLF line endings to fix builds on Windows
Close gh-3929
2018-01-09 10:50:09 -05:00
Timo Tijhof
ecd8ddea33
Tests: Add support for running unit tests via grunt with karma
- Update QUnit to 1.23.1
- Remove unused dl#dl from test/index.html
- Remove unused map#imgmap from test/index.html
- Ensure all urls to data use baseURI
- Add the 'grunt karma:main' task
  - customContextFile & customDebugFile
- Add 'npm run jenkins' script

Close gh-3744
Fixes gh-1999
2017-12-18 12:27:38 -05:00
Michał Gołębiowski-Owczarek
56e891dea1 Tests: Make Node tests work for paths with spaces in them
Without this patch Jenkins tests fail as jQuery job names there contain spaces,
e.g. "jQuery Core".

Closes gh-3821
2017-10-18 17:44:50 +02:00
Michał Gołębiowski-Owczarek
81be78e380 Build: increase timeout in Promises/A+ tests 10 times
The promises-aplus-tests sets up a default 200 ms Mocha timeout. This makes
our tests randomly fail on Jenkins. 2 seconds will be safer.

Closes gh-3791
2017-09-25 19:27:50 +02:00
Michał Gołębiowski-Owczarek
781647b182 Build: Drop cross-spawn, use child_process.spawn shell option 2017-09-25 19:27:50 +02:00
Michał Gołębiowski
4e50967725 Build: Make the @CODE-replacing regex more robust
The code replacing @CODE in wrapper.js was written so that it expected
both the code and the next line to start in the first column. This commit
adjusts the regex so to get rid of that assumption and to work properly
regardless of number of lines with comments after this block.

While this is technically not necessary for our code, contributors sometimes
re-format the wrapper file in their pull requests and the error
messages they get don't tell them what's the real problem with their code.

Closes gh-3429
2016-12-05 18:43:10 +01:00
Timmy Willison
52e24471c8
Core: expose noConflict in AMD mode
- For compability reasons, we had already added the global
  in AMD mode, but without noConflict. This adds back noConflict
  to AMD (which fixes noConflict mode in the tests).

Fixes gh-2930
2016-08-15 11:54:55 -04:00
Michał Gołębiowski
6e605afb1f Build: Fix the regex removing the ESLint comment from wrapper.js
The new regex from after the switch from JSHint to ESLint wasn't catching
the ESLint pragma correctly.

Also, the spacing of the pragma comment was updated to match other comments.
2016-07-13 10:49:13 +02:00
Oleg Gaidarenko
58c6ca9822 Build: ESLint details
Use eslint pragmas, fix new errors, etc

Closes gh-3148
2016-06-11 10:41:33 +03:00
Oleg Gaidarenko
a4474c9a00 Tests: Move promise/A+ adapters for tests to dedicated folder 2016-06-11 10:39:51 +03:00
Richard Gibson
356a3bccb0 Deferred: Separate the two paths in jQuery.when
Single- and no-argument calls act like Promise.resolve.
Multi-argument calls act like Promise.all.

Fixes gh-3029
Closes gh-3059
2016-05-02 12:30:31 -04:00
Michał Gołębiowski
3b356cfde4 Build: Strip the strict-mode related comment in exports/global.js
The comment (& the JSHint pragma) doesn't make sense in the context of the
full built file.

Closes gh-3078
2016-04-26 22:50:22 +02:00
Michał Gołębiowski
0652c4d6a2 Build: Strip excessive "use strict" pragmas when building
Fixes gh-3077
2016-04-26 22:50:18 +02:00
Richard Gibson
76084372c2 Deferred: Remove default callback context
Employs strict mode to simplify Deferred callback context handling.

Fixes gh-3060
Closes gh-3061
2016-04-23 00:30:48 -04:00
Timmy Willison
5cbb234dd3 Core: implement ready without Deferred
- Make jQuery.ready promise-compatible
- Gives up sync guarantee for post-ready callbacks

Fixes gh-1778
Fixes gh-1823
Close gh-2891
2016-04-04 11:26:22 -04:00
Oleg Gaidarenko
055cb7534e Build: try insight package to get info about custom builds
Fixes gh-2890
Closes gh-2988
2016-03-14 21:13:05 +03:00
Timmy Willison
4a098f4883 Build: combine intro and outro
Fixes gh-2975
Close gh-2976
2016-03-09 11:42:42 -05:00
Timmy Willison
5943f1d7ff Build: use hard-coded path to sizzle in selector-sizzle
Fixes gh-2898
2016-02-10 13:47:25 -08:00
Michał Gołębiowski
c7431c7793 Build: Drop testing on jsdom with Node 0.10 & 0.12
Fixes gh-2841
2016-02-10 12:57:49 +01:00
Michał Gołębiowski
abb5715807 Build: switch from win-spawn to cross-spawn
The win-spawn package is deprecated.

Refs gh-2877
Refs 67c96a59f5
2016-01-27 13:02:58 +01:00
Timmy Willison
cf7102c3f1 Release: push a custom slim build to the CDN
Fixes gh-2653
Close gh-2711
2015-11-16 11:22:20 -05:00
Martin Naumann
0c34e68843 Build: Fixed issue with base path that contain 'var'
Remove the cwd from the paths, so the regex doesn't kick in on "var"

Fixes gh-2450
Closes gh-2641
2015-10-12 18:17:12 +03:00
Michał Gołębiowski
2c7e9c9349 Tests: Add simple tests for Android 2.3
Fixes gh-2505
Closes gh-2509
Refs gh-2483
2015-09-08 18:03:49 +02:00
Michał Gołębiowski
dbb2daa8c3 Build: Don't install jsdom 3 on Node.js 0.10 & 0.12 by default
jsdom 3 requires Python & Visual Studio on Windows which is a significant
barrier to contributors. Newer jsdom versions don't require pre-compiling
but work only on io.js. This commit installs the new jsdom everywhere (it
does install in old Node.js, it just won't work) and executes Node-related
tests only on newer Nodes or if a working jsdom version is installed. The
latter can be achieved by running the `old_jsdom` task.

Node.js is merging with io.js soon so this will become a smaller problem over
time.

One drawback is our Jenkins setup runs on Node 0.10 so it won't be running
Node tests anymore. We have Travis set up on io.js, though so all PRs
have those tests run. When the new LTS Node.js arrives (as it soon merges
with io.js) we should update our Jenkins infrastructure so that it runs on this
new version.

Fixes gh-2519
Closes gh-2526
2015-09-08 17:42:38 +02:00
Oleg Gaidarenko
10fdad742a Build: Update jscs and lint files
Fixes gh-2056
2015-09-07 20:03:50 +03:00
Timmy Willison
63a577aa0b Build: space between curly and paren is optional
Fixes gh-2399
Close gh-2400
2015-06-19 13:40:11 -04:00