diff --git a/.eslintignore b/.eslintignore index 6d17eddbac7e7..f48cd9110889b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,12 +9,12 @@ out/** test/coverage/** # Code directories -**/*.extern.js build-system/tasks/visual-diff/snippets/*.js build-system/babel-plugins/**/fixtures/**/*.js build-system/server/app-index/test/*.js examples/** extensions/amp-a4a/0.1/test/testdata/** +src/purifier/noop.js testing/local-amp-chrome-extension/** third_party/** validator/** diff --git a/.eslintrc b/.eslintrc index d9491cccbe75f..25b51cccc6a1e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -81,6 +81,7 @@ "local/json-configuration": 2, "local/no-array-destructuring": 2, "local/no-deep-destructuring": 2, + "local/no-destructure-assignment-params": 2, "local/no-duplicate-import": 2, "local/no-duplicate-name-typedef": 2, "local/no-es2015-number-props": 2, @@ -92,9 +93,10 @@ "local/no-import-rename": 2, "local/no-is-amp-alt": 2, "local/no-log-array": 2, + "local/no-mixed-interpolation": 2, "local/no-mixed-operators": 2, "local/no-module-exports": 2, - "local/no-mixed-interpolation": 2, + "local/no-rest": 2, "local/no-spread": 2, "local/no-style-display": 2, "local/no-style-property-setting": 2, @@ -102,6 +104,8 @@ "local/no-unload-listener": 2, "local/prefer-deferred-promise": 0, "local/prefer-destructuring": 2, + "local/prefer-spread-props": 2, + "local/prefer-unnested-spread-objects": 2, "local/private-prop-names": 2, "local/query-selector": 2, "local/split-single-pass-comment": 2, @@ -191,6 +195,7 @@ ], "rules": { "require-jsdoc": 0, + "local/no-destructure-assignment-params": 0, "jsdoc/check-param-names": 0, "jsdoc/check-tag-names": 0, "jsdoc/check-types": 0, @@ -225,6 +230,20 @@ "process": false, "require": false } + }, + { + "files": ["**/*.extern.js"], + "rules": { + "no-var": 0, + "no-undef": 0, + "no-unused-vars": 0, + "prefer-const": 0, + "require-jsdoc": 0, + "jsdoc/check-tag-names": 0, + "local/closure-type-primitives": 0, + "local/no-duplicate-name-typedef": 0, + "google-camelcase/google-camelcase": 0 + } } ] } diff --git a/.github/ISSUE_TEMPLATE/cherry_pick_template.md b/.github/ISSUE_TEMPLATE/cherry_pick_template.md index d29afe0edaf85..b37c6689f6bbf 100644 --- a/.github/ISSUE_TEMPLATE/cherry_pick_template.md +++ b/.github/ISSUE_TEMPLATE/cherry_pick_template.md @@ -1,6 +1,6 @@ --- name: Cherry-pick template -about: Used to request a cherry-pick. See bit.ly/amp-cherry-pick +about: Used to request a cherry-pick. See go.amp.dev/cherry-picks title: "\U0001F338 Cherry-pick request for # into # (Pending)" labels: 'Type: Release' --- diff --git a/.github/ISSUE_TEMPLATE/release-tracking-issue.md b/.github/ISSUE_TEMPLATE/release-tracking-issue.md index 57a27912e8321..aab2d63487596 100644 --- a/.github/ISSUE_TEMPLATE/release-tracking-issue.md +++ b/.github/ISSUE_TEMPLATE/release-tracking-issue.md @@ -13,8 +13,8 @@ assignees: '' - [x] Release `[](https://github.com/ampproject/amphtml/releases/tag/)` is cut as a new canary release -- [ ] Release pushed to dev channel () -- [ ] Release pushed to 1% () -- [ ] Release pushed to production () +- [ ] Release promoted to Experimental and Beta (opt-in) channels () +- [ ] Release promoted to Experimental and Beta (1% traffic) channels () +- [ ] Release promoted to Stable channel () -See the [release documentation](https://github.com/ampproject/amphtml/blob/master/contributing/release-schedule.md) for more information on the release process, including how to test changes in the Dev Channel. +See the [release documentation](https://github.com/ampproject/amphtml/blob/master/contributing/release-schedule.md) for more information on the release process, including how to test changes in the Experimental channel. -If you find a bug in this build, please file an [issue](https://github.com/ampproject/amphtml/issues/new). If you believe the bug should be fixed in this build, follow the instructions in the [cherry picks documentation](https://bit.ly/amp-cherry-pick). +If you find a bug in this build, please file an [issue](https://github.com/ampproject/amphtml/issues/new). If you believe the bug should be fixed in this build, follow the instructions in the [cherry picks documentation](https://go.amp.dev/cherry-picks). diff --git a/.github/ISSUE_TEMPLATE/release_issue_template.md b/.github/ISSUE_TEMPLATE/release_issue_template.md deleted file mode 100644 index 5834b8c12f754..0000000000000 --- a/.github/ISSUE_TEMPLATE/release_issue_template.md +++ /dev/null @@ -1,37 +0,0 @@ -# Release tracking issue - - - -- [x] Release `[](https://github.com/ampproject/amphtml/releases/tag/)` is cut as a new canary release -- [ ] Release pushed to dev channel () -- [ ] Release pushed to 1% () -- [ ] Release pushed to production () - - - -See the [release documentation](https://github.com/ampproject/amphtml/blob/master/contributing/release-schedule.md) for more information on the release process, including how to test changes in the Dev Channel. - -If you find a bug in this build, please file an [issue](https://github.com/ampproject/amphtml/issues/new). If you believe the bug should be fixed in this build, follow the instructions in the [cherry picks documentation](https://bit.ly/amp-cherry-pick). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 041b7943a35b9..047bd6f66d4ed 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,6 +9,8 @@ - Mention the GitHub issue that is being addressed by the pull request. - The keywords `Fixes`, `Closes`, or `Resolves` followed the issue number will automatically close the issue. +> NOTE: All non-trivial changes (like introducing new features or components) should have an associated issue or reference an I2I (intent-to-implement: go.amp.dev/i2i). Please read through the contribution process (go.amp.dev/contributing/code) for more information. + # Example of a good description: - Implement aspect X diff --git a/.gitignore b/.gitignore index 91c1236ac33e8..9f20a5831497d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .DS_Store .g4ignore -build +build/ .amp-build c /dist @@ -30,4 +30,6 @@ firebase .firebaserc firebase.json .firebase/ -extensions/amp-analytics/0.1/vendors/*.json +src/purifier/dist +build-system/tasks/performance/cache +build-system/tasks/performance/results.json diff --git a/.renovaterc.json b/.renovaterc.json index 2e487ecad398f..a2a3e8157792e 100644 --- a/.renovaterc.json +++ b/.renovaterc.json @@ -12,6 +12,7 @@ "package.json", "build-system/tasks/e2e/package.json", "build-system/tasks/visual-diff/package.json", + "src/purifier/package.json", "validator/package.json" ] } diff --git a/.travis.yml b/.travis.yml index 3b4cc1058b824..73771831c8a13 100644 --- a/.travis.yml +++ b/.travis.yml @@ -93,17 +93,20 @@ jobs: name: 'Experiment A Tests' script: - unbuffer node build-system/pr-check/experiment-tests.js --experiment=experimentA + cache: false - stage: experiment name: 'Experiment B Tests' script: - unbuffer node build-system/pr-check/experiment-tests.js --experiment=experimentB + cache: false - stage: experiment name: 'Experiment C Tests' script: - unbuffer node build-system/pr-check/experiment-tests.js --experiment=experimentC + cache: false before_cache: - # do not store cache for pr builds - - if [[ $TRAVIS_EVENT_TYPE == pull_request ]]; then exit $TRAVIS_TEST_RESULT ; fi + # do not store cache for pr builds or experiment stage builds + - if [[ $TRAVIS_EVENT_TYPE == pull_request ]] || [[ $TRAVIS_BUILD_STAGE_NAME == experiment ]]; then exit $TRAVIS_TEST_RESULT ; fi cache: directories: - node_modules diff --git a/.vscode/settings.json b/.vscode/settings.json index 338b89a1c4e39..bd3f8ab9b4192 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,8 @@ ".eslintrc": "json", ".prettierrc": "json", ".renovaterc.json": "json", + + // Enable YAML auto-formatting for these files. ".codecov.yml": "yaml", ".lando.yml": "yaml", ".lgtm.yml": "yaml", @@ -17,7 +19,7 @@ // Auto-fix JS files with ESLint using amphtml's custom settings. Needs // https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint - "eslint.autoFixOnSave": true, + "editor.codeActionsOnSave": {"source.fixAll.eslint": true}, "[js]": {"editor.formatOnSave": false}, // Auto-fix non-JS files with Prettier using amphtml's custom settings. Needs diff --git a/3p/3p.js b/3p/3p.js index a5b3eb0ae8cfa..7385178b7fea5 100644 --- a/3p/3p.js +++ b/3p/3p.js @@ -232,7 +232,8 @@ export function validateData(data, mandatoryFields, opt_optionalFields) { allowedFields = allowedFields.concat(field); } else { userAssert( - data[field], + // Allow zero values for height, width etc. + data[field] != null, 'Missing attribute for %s: %s.', data.type, field diff --git a/3p/OWNERS b/3p/OWNERS index 9cc48924e3979..e681110b1334b 100644 --- a/3p/OWNERS +++ b/3p/OWNERS @@ -4,7 +4,10 @@ { rules: [ { - owners: [{name: 'ampproject/wg-ads'}], + owners: [ + {name: 'ampproject/wg-ads'}, + {name: 'ampproject/wg-ui-and-a11y'}, + ], }, ], } diff --git a/3p/README.md b/3p/README.md index 145340275765f..49b5af83fbe96 100644 --- a/3p/README.md +++ b/3p/README.md @@ -66,5 +66,5 @@ Review the [ads/README](../ads/README.md) for further details on ad integration. You should ensure there are integration tests for your extension. These should be added to the AMP repo where it makes sense. In some cases this won't be possible because it relies on bringing up third-party infrastructure. In these cases you should maintain testing for the extension on your -infrastructure against both production AMP and [canary](https://github.com/ampproject/amphtml/blob/master/contributing/release-schedule.md#amp-dev-channel). +infrastructure against both production AMP and [canary](https://github.com/ampproject/amphtml/blob/master/contributing/release-schedule.md#amp-experimental-and-beta-channels). Upon any monitored failures, an escalation can be raised in [regular AMP communication channel](https://github.com/ampproject/amphtml/blob/master/CONTRIBUTING.md#discussion-channels). diff --git a/3p/beopinion.js b/3p/beopinion.js index f381880166ca0..d0e4a9a8e3ccd 100644 --- a/3p/beopinion.js +++ b/3p/beopinion.js @@ -88,6 +88,9 @@ function createContainer(global, data) { function getBeOpinionAsyncInit(global, accountId) { const {context} = global; return function() { + context.onResizeDenied(function(requestedHeight, requestedWidth) { + context.requestResize(requestedWidth, requestedHeight); + }); global.BeOpinionSDK.init({ account: accountId, onContentReceive: function(hasContent) { @@ -100,7 +103,6 @@ function getBeOpinionAsyncInit(global, accountId) { onHeightChange: function(newHeight) { const c = global.document.getElementById('c'); const boundingClientRect = c./*REVIEW*/ getBoundingClientRect(); - context.onResizeDenied(context.requestResize.bind(context)); context.requestResize(boundingClientRect.width, newHeight); }, }); diff --git a/3p/iframe-transport-client.js b/3p/iframe-transport-client.js index fadfa8b76ff17..3fca0d886f448 100644 --- a/3p/iframe-transport-client.js +++ b/3p/iframe-transport-client.js @@ -182,7 +182,7 @@ export class IframeTransportContext { this.iframeMessagingClient_./*OK*/ sendMessage( MessageType.IFRAME_TRANSPORT_RESPONSE, /** @type {!JsonObject} */ - (Object.assign({message: data}, this.baseMessage_)) + ({message: data, ...this.baseMessage_}) ); } } diff --git a/3p/integration.js b/3p/integration.js index 231e6df993289..2a3d4cb1e72f2 100644 --- a/3p/integration.js +++ b/3p/integration.js @@ -85,6 +85,7 @@ import {adplugg} from '../ads/adplugg'; import {adpon} from '../ads/adpon'; import {adreactor} from '../ads/adreactor'; import {adsensor} from '../ads/adsensor'; +import {adservsolutions} from '../ads/adservsolutions'; import {adsloom} from '../ads/adsloom'; import {adsnative} from '../ads/adsnative'; import {adspeed} from '../ads/adspeed'; @@ -114,6 +115,7 @@ import {blade} from '../ads/blade'; import {brainy} from '../ads/brainy'; import {bringhub} from '../ads/bringhub'; import {broadstreetads} from '../ads/broadstreetads'; +import {byplay} from '../ads/byplay'; import {caajainfeed} from '../ads/caajainfeed'; import {capirs} from '../ads/capirs'; import {caprofitx} from '../ads/caprofitx'; @@ -187,6 +189,7 @@ import {mox} from '../ads/mox'; import {mytarget} from '../ads/mytarget'; import {mywidget} from '../ads/mywidget'; import {nativeroll} from '../ads/nativeroll'; +import {nativery} from '../ads/nativery'; import {nativo} from '../ads/nativo'; import {navegg} from '../ads/navegg'; import {nend} from '../ads/nend'; @@ -242,7 +245,9 @@ import {sovrn} from '../ads/sovrn'; import {speakol} from '../ads/speakol'; import {spotx} from '../ads/spotx'; import {springAds} from '../ads/springAds'; +import {ssp} from '../ads/ssp'; import {strossle} from '../ads/strossle'; +import {sulvo} from '../ads/sulvo'; import {sunmedia} from '../ads/sunmedia'; import {svknative} from '../ads/svknative'; import {swoop} from '../ads/swoop'; @@ -258,6 +263,7 @@ import {ucfunnel} from '../ads/ucfunnel'; import {unruly} from '../ads/unruly'; import {uzou} from '../ads/uzou'; import {valuecommerce} from '../ads/valuecommerce'; +import {vdoai} from '../ads/vdoai'; import {videointelligence} from '../ads/videointelligence'; import {videonow} from '../ads/videonow'; import {viralize} from '../ads/viralize'; @@ -305,6 +311,7 @@ const AMP_EMBED_ALLOWED = { mgid: true, miximedia: true, mywidget: true, + nativery: true, lentainform: true, opinary: true, outbrain: true, @@ -358,6 +365,7 @@ register('adplugg', adplugg); register('adpon', adpon); register('adreactor', adreactor); register('adsensor', adsensor); +register('adservsolutions', adservsolutions); register('adsloom', adsloom); register('adsnative', adsnative); register('adspeed', adspeed); @@ -389,6 +397,7 @@ register('bodymovinanimation', bodymovinanimation); register('brainy', brainy); register('bringhub', bringhub); register('broadstreetads', broadstreetads); +register('byplay', byplay); register('caajainfeed', caajainfeed); register('capirs', capirs); register('caprofitx', caprofitx); @@ -468,6 +477,7 @@ register('mox', mox); register('mytarget', mytarget); register('mywidget', mywidget); register('nativeroll', nativeroll); +register('nativery', nativery); register('nativo', nativo); register('navegg', navegg); register('nend', nend); @@ -514,6 +524,7 @@ register('sekindo', sekindo); register('sharethrough', sharethrough); register('shemedia', shemedia); register('sklik', sklik); +register('ssp', ssp); register('slimcutmedia', slimcutmedia); register('smartadserver', smartadserver); register('smartclip', smartclip); @@ -525,6 +536,7 @@ register('sovrn', sovrn); register('spotx', spotx); register('springAds', springAds); register('strossle', strossle); +register('sulvo', sulvo); register('sunmedia', sunmedia); register('svknative', svknative); register('swoop', swoop); @@ -541,6 +553,7 @@ register('ucfunnel', ucfunnel); register('unruly', unruly); register('uzou', uzou); register('valuecommerce', valuecommerce); +register('vdoai', vdoai); register('videointelligence', videointelligence); register('videonow', videonow); register('viqeoplayer', viqeoplayer); diff --git a/3p/viqeoplayer.js b/3p/viqeoplayer.js index 787b930f3e17a..28211c0501922 100644 --- a/3p/viqeoplayer.js +++ b/3p/viqeoplayer.js @@ -30,6 +30,13 @@ function viqeoPlayerInitLoaded(global, VIQEO) { VIQEO['subscribeTracking'](params => { viqeoPlayerInstance = params['player']; }, 'Player:added'); + VIQEO['subscribeTracking'](() => { + sendMessage('updatePlayedRanges', viqeoPlayerInstance['getPlayedRanges']()); + sendMessage('updateCurrentTime', viqeoPlayerInstance['getCurrentTime']()); + }, 'Player:currentTimeUpdated'); + VIQEO['subscribeTracking'](() => { + sendMessage('updateDuration', viqeoPlayerInstance['getDuration']()); + }, 'Player:durationUpdated'); VIQEO['createPlayer']({ videoId: data['videoid'], profileId: data['profileid'], @@ -38,16 +45,16 @@ function viqeoPlayerInitLoaded(global, VIQEO) { global.addEventListener('message', parseMessage, false); - subscribe('videoLoaded', 'ready'); - subscribe('previewLoaded', 'ready'); - subscribe('started', 'started'); + subscribe('ready', 'ready'); subscribe('paused', 'pause'); + subscribe('started', 'play'); subscribe('played', 'play'); subscribe('replayed', 'play'); - subscribeTracking({ - Mute: 'mute', - Unmute: 'unmute', - }); + subscribe('ended', 'end'); + subscribe('advStarted', 'startAdvert'); + subscribe('advEnded', 'endAdvert'); + subscribe('muted', 'mute'); + subscribe('unmuted', 'unmute'); /** * Subscribe on viqeo's events @@ -61,22 +68,6 @@ function viqeoPlayerInitLoaded(global, VIQEO) { }, `Player:${playerEventName}`); } - /** - * Subscribe viqeo's tracking - * @param {Object.} eventsDescription - * @private - */ - function subscribeTracking(eventsDescription) { - VIQEO['subscribeTracking'](params => { - const name = - params && params['trackingParams'] && params['trackingParams'].name; - const targetEventName = eventsDescription[name]; - if (targetEventName) { - sendMessage(targetEventName); - } - }, 'Player:userAction'); - } - const sendMessage = (eventName, value = null) => { const {parent} = global; const message = /** @type {JsonObject} */ ({ diff --git a/METRICS.md b/METRICS.md index 9362a86583331..198a9296cc651 100644 --- a/METRICS.md +++ b/METRICS.md @@ -12,11 +12,11 @@ Average Travis build time over the last 90 days ![Presubmit Latency](https://amp-project-metrics.appspot.com/api/plot/PresubmitLatencyMetric.png) -## Release Cherrypick Count +## Cherrypick Issue Count -Number of cherry-picks in releases over the last 90 days +Number of cherry-pick issues in the last 90 days -![Release Cherrypick Count](https://amp-project-metrics.appspot.com/api/plot/ReleaseCherrypickCountMetric.png) +![Cherrypick Issue Count](https://amp-project-metrics.appspot.com/api/plot/CherrypickIssueCountMetric.png) ## Release Granularity diff --git a/README.md b/README.md index 247bd809de08f..3bf2174029e40 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![Build Status](https://img.shields.io/travis/ampproject/amphtml/master.svg?logo=Travis%20CI&logoColor=white&style=flat-square 'Build Status')](https://travis-ci.org/ampproject/amphtml/builds) [![GitHub Release](https://img.shields.io/github/release/ampproject/amphtml.svg?logo=GitHub&style=flat-square 'GitHub Release')](https://github.com/ampproject/amphtml/releases/latest) -[![Contributors](https://img.shields.io/github/contributors-anon/ampproject/amphtml.svg?logo=GitHub&style=flat-square 'Contributors')](https://github.com/ampproject/amphtml/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/ampproject/amphtml.svg?logo=GitHub&style=flat-square 'Commits')](https://github.com/ampproject/amphtml/pulse/monthly) [![Badges](https://img.shields.io/badge/badges-16-brightgreen?logo=GitHub&style=flat-square)](#) @@ -14,7 +13,7 @@ Metrics [![Absolute Code Coverage](https://img.shields.io/endpoint.svg?logo=Codecov&logoColor=white&style=flat-square&url=https%3A%2F%2Famp-project-metrics.appspot.com%2Fapi%2Fbadge%2FAbsoluteCoverageMetric 'Test coverage for the repository as computed by CodeCov')](https://codecov.io/gh/ampproject/amphtml/) [![Presubmit Latency](https://img.shields.io/endpoint.svg?logo=Travis%20CI&logoColor=white&style=flat-square&url=https%3A%2F%2Famp-project-metrics.appspot.com%2Fapi%2Fbadge%2FPresubmitLatencyMetric 'Average Travis build time over the last 90 days')](https://travis-ci.org/ampproject/amphtml/builds) -[![Release Cherrypick Count](https://img.shields.io/endpoint.svg?logo=GitHub&logoColor=white&style=flat-square&url=https%3A%2F%2Famp-project-metrics.appspot.com%2Fapi%2Fbadge%2FReleaseCherrypickCountMetric 'Number of cherry-picks in releases over the last 90 days')](https://github.com/ampproject/amphtml/issues?utf8=%E2%9C%93&q=is%3Aissue+title%3A+%22Cherry-pick%22) +[![Cherrypick Issue Count](https://img.shields.io/endpoint.svg?logo=GitHub&logoColor=white&style=flat-square&url=https%3A%2F%2Famp-project-metrics.appspot.com%2Fapi%2Fbadge%2FCherrypickIssueCountMetric 'Number of cherry-pick issues in the last 90 days')](https://github.com/ampproject/amphtml/issues?utf8=%E2%9C%93&q=is%3Aissue+title%3A+%22Cherry-pick%22) [![Release Granularity](https://img.shields.io/endpoint.svg?logo=GitHub&logoColor=white&style=flat-square&url=https%3A%2F%2Famp-project-metrics.appspot.com%2Fapi%2Fbadge%2FReleaseGranularityMetric 'Average commits per release over the last 90 days')](https://github.com/ampproject/amphtml/releases) [![Travis Greenness](https://img.shields.io/endpoint.svg?logo=Travis%20CI&logoColor=white&style=flat-square&url=https%3A%2F%2Famp-project-metrics.appspot.com%2Fapi%2Fbadge%2FTravisGreennessMetric 'Percentage of green Travis builds over the last 90 days')](https://travis-ci.org/ampproject/amphtml/builds) [![Travis Flakiness](https://img.shields.io/endpoint.svg?logo=Travis%20CI&logoColor=white&style=flat-square&url=https%3A%2F%2Famp-project-metrics.appspot.com%2Fapi%2Fbadge%2FTravisFlakinessMetric 'Percentage of flaky Travis builds over the last 90 days')](https://travis-ci.org/ampproject/amphtml/builds) @@ -65,7 +64,7 @@ AMP is an open source project, and we'd love your help making it better! ## Other useful information -- [AMP's release documentation](contributing/release-schedule.md) provides details on how and when AMP releases new versions, including [how to know when a change is live in production](https://github.com/ampproject/amphtml/blob/master/contributing/release-schedule.md#determining-if-your-change-is-in-production). +- [AMP's release documentation](contributing/release-schedule.md) provides details on how and when AMP releases new versions, including [how to know when a change is live in a release](https://github.com/ampproject/amphtml/blob/master/contributing/release-schedule.md#determining-if-your-change-is-in-a-release). - [AMP's roadmap](https://amp.dev/community/roadmap) provides details on some of the significant projects we are working on. - The [AMP meta repository](https://github.com/ampproject/meta) has information _about_ the AMP open source project, including AMP's [governance](https://github.com/ampproject/meta/blob/master/GOVERNANCE.md). - [AMP's code of conduct](https://github.com/ampproject/meta/blob/master/CODE_OF_CONDUCT.md) documents how all members, committers and volunteers in the community are required to act. AMP strives for a positive and growing project community that provides a safe environment for everyone. diff --git a/ads/README.md b/ads/README.md index 8453170cbd3d8..2d5fa355b9441 100644 --- a/ads/README.md +++ b/ads/README.md @@ -361,6 +361,7 @@ To speed up the review process, please run `gulp lint` and `gulp check-types`, t ### Other tips +- Add **cc ampproject/wg-ads** in all pull request's descriptions. - It's highly recommended to maintain [an integration test outside AMP repo](../3p/README.md#adding-proper-integration-tests). - Please consider implementing the `render-start` and `no-content-available` APIs (see [Available APIs](#available-apis)), which helps AMP to provide user a much better ad loading experience. - [CLA](../CONTRIBUTING.md#contributing-code): for anyone who has trouble to pass the automatic CLA check in a pull request, try to follow the guidelines provided by the CLA Bot. Common mistakes are: diff --git a/ads/_config.js b/ads/_config.js index 2668274fafa4a..d8714b864aeef 100755 --- a/ads/_config.js +++ b/ads/_config.js @@ -177,6 +177,9 @@ const adConfig = jsonConfiguration({ clientIdScope: 'amp_ecid_adensor', renderStartImplemented: true, }, + + 'adservsolutions': {}, + 'adsloom': { clientIdScope: 'AMP_ECID_ADSLOOM', }, @@ -333,6 +336,8 @@ const adConfig = jsonConfiguration({ prefetch: 'https://cdn.broadstreetads.com/init-2.min.js', }, + 'byplay': {}, + 'caajainfeed': { prefetch: ['https://cdn.amanad.adtdp.com/sdk/ajaamp.js'], preconnect: ['https://ad.amanad.adtdp.com'], @@ -718,6 +723,10 @@ const adConfig = jsonConfiguration({ prefetch: 'https://cdn01.nativeroll.tv/js/seedr-player.min.js', }, + 'nativery': { + preconnect: 'https://cdn.nativery.com', + }, + 'nativo': { prefetch: 'https://s.ntv.io/serve/load.js', }, @@ -992,6 +1001,12 @@ const adConfig = jsonConfiguration({ renderStartImplemented: true, }, + 'ssp': { + prefetch: 'https://ssp.imedia.cz/static/js/ssp.js', + renderStartImplemented: true, + consentHandlingOverride: true, + }, + 'strossle': { preconnect: [ 'https://amp.spklw.com', @@ -1074,6 +1089,11 @@ const adConfig = jsonConfiguration({ renderStartImplemented: true, }, + 'vdoai': { + prefetch: 'https://a.vdo.ai/core/dependencies_amp/vdo.min.js', + renderStartImplemented: true, + }, + 'videointelligence': { preconnect: 'https://s.vi-serve.com', renderStartImplemented: true, @@ -1198,6 +1218,8 @@ const adConfig = jsonConfiguration({ prefetch: 'https://dup.baidustatic.com/js/dm.js', renderStartImplemented: true, }, + + 'sulvo': {}, }); export {adConfig}; diff --git a/ads/ads.extern.js b/ads/ads.extern.js index 7eb17326350d6..91d270ded2e39 100644 --- a/ads/ads.extern.js +++ b/ads/ads.extern.js @@ -19,15 +19,15 @@ // HACK. Define application types used in default AMP externs // that are not in the 3p code. /** @constructor */ -function BaseElement$$module$src$base_element() {}; +function BaseElement$$module$src$base_element() {} /** @constructor */ -function AmpAdXOriginIframeHandler$$module$extensions$amp_ad$0_1$amp_ad_xorigin_iframe_handler() {}; +function AmpAdXOriginIframeHandler$$module$extensions$amp_ad$0_1$amp_ad_xorigin_iframe_handler() {} /** @constructor */ -function AmpAd3PImpl$$module$extensions$amp_ad$0_1$amp_ad_3p_impl() {}; +function AmpAd3PImpl$$module$extensions$amp_ad$0_1$amp_ad_3p_impl() {} /** @constructor */ -function AmpA4A$$module$extensions$amp_a4a$0_1$amp_a4a() {}; +function AmpA4A$$module$extensions$amp_a4a$0_1$amp_a4a() {} /** @constructor */ -function AmpAdUIHandler$$module$extensions$amp_ad$0_1$amp_ad_ui() {}; +function AmpAdUIHandler$$module$extensions$amp_ad$0_1$amp_ad_ui() {} // Long list of, uhm, stuff the ads code needs to compile. // All unquoted external properties need to be added here. @@ -54,45 +54,47 @@ data.embedtype; data.src; //twitter.js -data.tweetid +data.tweetid; //mathml.js -data.formula -var mathjax -mathjax.Hub -mathjax.Hub.Config -mathjax.Hub.Queue -window.MathJax +data.formula; +var mathjax; +mathjax.Hub; +mathjax.Hub.Config; +mathjax.Hub.Queue; +window.MathJax; //3d-gltf/index.js var THREE; -THREE.LoaderUtils -THREE.LoaderUtils.extractUrlBase +THREE.LoaderUtils; +THREE.LoaderUtils.extractUrlBase; THREE.WebGLRenderer = class { /** @param {!JsonObject} opts */ constructor(opts) { - /** @type {?Element} */ this.domElement = null;}}; -THREE.WebGLRenderer.prototype.setSize -THREE.WebGLRenderer.prototype.setPixelRatio -THREE.WebGLRenderer.prototype.setClearColor -THREE.WebGLRenderer.prototype.render + /** @type {?Element} */ this.domElement = null; + } +}; +THREE.WebGLRenderer.prototype.setSize; +THREE.WebGLRenderer.prototype.setPixelRatio; +THREE.WebGLRenderer.prototype.setClearColor; +THREE.WebGLRenderer.prototype.render; /** @type {boolean} */ -THREE.WebGLRenderer.prototype.gammaOutput +THREE.WebGLRenderer.prototype.gammaOutput; /** @type {number} */ -THREE.WebGLRenderer.prototype.gammaFactor +THREE.WebGLRenderer.prototype.gammaFactor; THREE.Light = class extends THREE.Object3D {}; THREE.DirectionalLight = class extends THREE.Light {}; THREE.AmbientLight = class extends THREE.Light {}; THREE.Box3 = class {}; -THREE.Box3.prototype.getSize -THREE.Box3.prototype.getCenter -THREE.Box3.prototype.setFromObject -THREE.Box3.prototype.min -THREE.Box3.prototype.max +THREE.Box3.prototype.getSize; +THREE.Box3.prototype.getCenter; +THREE.Box3.prototype.setFromObject; +THREE.Box3.prototype.min; +THREE.Box3.prototype.max; THREE.Vector3 = class { /** @param {number=} opt_x @@ -100,25 +102,27 @@ THREE.Vector3 = class { * @param {number=} opt_z */ constructor(opt_x, opt_y, opt_z) {} }; -THREE.Vector3.prototype.lerpVectors -THREE.Vector3.prototype.copy -THREE.Vector3.prototype.clone -THREE.Vector3.prototype.subVectors -THREE.Vector3.prototype.multiplyScalar -THREE.Vector3.prototype.setFromMatrixColumn -THREE.Vector3.prototype.add -THREE.Vector3.prototype.set -THREE.Vector3.prototype.applyQuaternion -THREE.Vector3.prototype.setFromSpherical -THREE.Vector3.prototype.distanceToSquared -THREE.Vector3.prototype.length -THREE.Vector3.prototype.fromArray +THREE.Vector3.prototype.lerpVectors; +THREE.Vector3.prototype.copy; +THREE.Vector3.prototype.clone; +THREE.Vector3.prototype.subVectors; +THREE.Vector3.prototype.multiplyScalar; +THREE.Vector3.prototype.setFromMatrixColumn; +THREE.Vector3.prototype.add; +THREE.Vector3.prototype.set; +THREE.Vector3.prototype.applyQuaternion; +THREE.Vector3.prototype.setFromSpherical; +THREE.Vector3.prototype.distanceToSquared; +THREE.Vector3.prototype.length; +THREE.Vector3.prototype.fromArray; THREE.Euler = class { constructor() { this.x = 0; this.y = 0; - this.z = 0;}}; + this.z = 0; + } +}; THREE.Euler.prototype.set; @@ -126,21 +130,25 @@ THREE.Object3D = class { constructor() { this.position = new THREE.Vector3(); this.rotation = new THREE.Euler(); - this.children = [];}}; + this.children = []; + } +}; -THREE.Object3D.prototype.applyMatrix -THREE.Object3D.prototype.add -THREE.Object3D.prototype.updateMatrixWorld -THREE.Object3D.prototype.lookAt -THREE.Object3D.prototype.clone +THREE.Object3D.prototype.applyMatrix; +THREE.Object3D.prototype.add; +THREE.Object3D.prototype.updateMatrixWorld; +THREE.Object3D.prototype.lookAt; +THREE.Object3D.prototype.clone; THREE.OrbitControls = class { /** @param {THREE.Camera} camera * @param {Element} domElement */ constructor(camera, domElement) { - this.target = new THREE.Vector3(); }}; -THREE.OrbitControls.prototype.update -THREE.OrbitControls.prototype.addEventListener + this.target = new THREE.Vector3(); + } +}; +THREE.OrbitControls.prototype.update; +THREE.OrbitControls.prototype.addEventListener; THREE.Scene = class extends THREE.Object3D {}; THREE.Group = class extends THREE.Object3D {}; @@ -152,16 +160,20 @@ THREE.Camera = class extends THREE.Object3D { this.far = 0; this.near = 0; this.aspect = 0; - this.zoom = 0;}}; -THREE.Camera.prototype.updateProjectionMatrix -THREE.Camera.prototype.setFromUnitVectors + this.zoom = 0; + } +}; +THREE.Camera.prototype.updateProjectionMatrix; +THREE.Camera.prototype.setFromUnitVectors; THREE.PerspectiveCamera = class extends THREE.Camera {}; THREE.GLTFLoader = class { constructor() { - this.crossOrigin = false;}}; -THREE.GLTFLoader.prototype.load + this.crossOrigin = false; + } +}; +THREE.GLTFLoader.prototype.load; // Under ads/google folder @@ -198,7 +210,7 @@ data.overrideHeight; data.height; data.multiSizeValidation; data.categoryExclusions; -data.categoryExclusions.length;; +data.categoryExclusions.length; data.cookieOptions; data.tagForChildDirectedTreatment; data.targeting; @@ -218,7 +230,7 @@ google.ima.AdsLoader; google.ima.AdsLoader.getSettings; google.ima.AdsLoader.requestAds; google.ima.AdsManagerLoadedEvent; -google.ima.AdsManagerLoadedEvent.Type +google.ima.AdsManagerLoadedEvent.Type; google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED; google.ima.AdsManagerLoadedEvent.getAdsManager; google.ima.AdErrorEvent; @@ -419,7 +431,7 @@ data.parameters; data.queue; // imedia.js -data.positions +data.positions; // imonomy.js data.pid; @@ -508,7 +520,7 @@ Guoshi.queryAd.amp; Guoshi.queryAd.amp.setup; // openadstream.js -data.adhost +data.adhost; data.sitepage; data.pos; data.query; @@ -612,8 +624,8 @@ data.z; data.tf; // swoop.js -var Swoop -Swoop.announcePlace +var Swoop; +Swoop.announcePlace; // taboola.js data.referrer; diff --git a/ads/adservsolutions.js b/ads/adservsolutions.js new file mode 100644 index 0000000000000..5a5a1e1c9c644 --- /dev/null +++ b/ads/adservsolutions.js @@ -0,0 +1,33 @@ +/** + * Copyright 2015 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {validateData, writeScript} from '../3p/3p'; + +/** + * @param {!Window} global + * @param {!Object} data + */ +export function adservsolutions(global, data) { + validateData(data, [], ['client', 'zid']); + global['ABNS'] = + global['ABNS'] || + function() { + (global['ABNSl'] = global['ABNSl'] || []).push(arguments); + }; + global['ABNSh'] = data.client; + writeScript(global, 'https://cdn.' + global['ABNSh'] + '/libs/b.js'); + global['ABNS']('c', {id: data.zid + '&o=a'}); +} diff --git a/ads/adservsolutions.md b/ads/adservsolutions.md new file mode 100644 index 0000000000000..44ca351e89fd8 --- /dev/null +++ b/ads/adservsolutions.md @@ -0,0 +1,39 @@ + + +# AdServSolution + +## Example + +```html + + +``` + +## Configuration + +For details on the configuration semantics, please contact the ad network. + +Supported parameters: + +- `data-client`: ad server client +- `data-zid`: ad zone id diff --git a/ads/blade.js b/ads/blade.js index 16966a8be7022..dba58e037bb24 100644 --- a/ads/blade.js +++ b/ads/blade.js @@ -34,7 +34,7 @@ export function blade(global, data) { const marcosObj = tryParseJson(data['blade_macros']) || {}; marcosObj['rand'] = Math.random().toString(); marcosObj['page_url'] = marcosObj['page_url'] || global.context.canonicalUrl; - const macros = Object.assign({}, marcosObj); + const macros = {...marcosObj}; macros.width = data.width; macros.height = data.height; diff --git a/ads/byplay.js b/ads/byplay.js new file mode 100644 index 0000000000000..a70bde7501a4d --- /dev/null +++ b/ads/byplay.js @@ -0,0 +1,28 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {loadScript, validateData} from '../3p/3p'; + +/** + * @param {!Window} global + * @param {!Object} data + */ +export function byplay(global, data) { + validateData(data, ['vastUrl']); + + global.BYPLAY_VAST_URL = data['vastUrl']; + + loadScript(global, 'https://cdn.byplay.net/amp-byplay-v2.js'); +} diff --git a/ads/byplay.md b/ads/byplay.md new file mode 100644 index 0000000000000..bd3f130382779 --- /dev/null +++ b/ads/byplay.md @@ -0,0 +1,37 @@ + + +# ByPlay + +## Example + +```html + + +``` + +## Configuration + +For configuration details and to generate your tags, please contact email: [byplayers@tsumikiinc.com](mailto:byplayers@tsumikiinc.com). + +Required parameters: + +- `data-vast-url` diff --git a/ads/capirs.js b/ads/capirs.js index 0b7e4a8573607..4987dc63e883d 100644 --- a/ads/capirs.js +++ b/ads/capirs.js @@ -67,7 +67,6 @@ export function capirs(global, data) { }, }; - loadScript(global, '//ssp.rambler.ru/lpdid.js'); loadScript(global, '//ssp.rambler.ru/capirs_async.js'); } diff --git a/ads/google/a4a/line-delimited-response-handler.js b/ads/google/a4a/line-delimited-response-handler.js index 16292d4f0d6c4..4d83a4975cf57 100644 --- a/ads/google/a4a/line-delimited-response-handler.js +++ b/ads/google/a4a/line-delimited-response-handler.js @@ -22,7 +22,6 @@ import {tryParseJson} from '../../../src/json'; * @param {!Window} win * @param {!Response} response * @param {function(string, boolean)} lineCallback - * @private */ export function lineDelimitedStreamer(win, response, lineCallback) { let line = ''; @@ -71,7 +70,6 @@ export function lineDelimitedStreamer(win, response, lineCallback) { * Given each line, groups such that the first is JSON parsed and second * html unescaped. * @param {function(string, !Object, boolean)} callback - * @private * @return {function(string, boolean)} */ export function metaJsonCreativeGrouper(callback) { diff --git a/ads/google/a4a/test/test-utils.js b/ads/google/a4a/test/test-utils.js index 18a777c72bcf9..091d4c5ea00e6 100644 --- a/ads/google/a4a/test/test-utils.js +++ b/ads/google/a4a/test/test-utils.js @@ -257,10 +257,10 @@ describe('Google A4A utils', () => { }); describe('#getAmpRuntimeTypeParameter', () => { - it('should specify that this is canary', () => { + it('should specify that this is experimental', () => { expect( getAmpRuntimeTypeParameter({ - AMP_CONFIG: {type: 'canary'}, + AMP_CONFIG: {type: 'experimental'}, location: {origin: 'https://www-example-com.cdn.ampproject.org'}, }) ).to.equal('2'); @@ -299,7 +299,7 @@ describe('Google A4A utils', () => { it('should not have `art` parameter when canonical', () => { expect( getAmpRuntimeTypeParameter({ - AMP_CONFIG: {type: 'canary'}, + AMP_CONFIG: {type: 'experimental'}, location: {origin: 'https://www.example.com'}, }) ).to.be.null; diff --git a/ads/google/a4a/utils.js b/ads/google/a4a/utils.js index df24ffb2f54e3..f0936823a7799 100644 --- a/ads/google/a4a/utils.js +++ b/ads/google/a4a/utils.js @@ -830,7 +830,7 @@ export function getBinaryTypeNumericalCode(type) { { 'production': '0', 'control': '1', - 'canary': '2', + 'experimental': '2', 'rc': '3', 'experimentA': '10', 'experimentB': '11', diff --git a/ads/gumgum.js b/ads/gumgum.js index 615ac9a2f87dc..bf106176e6504 100644 --- a/ads/gumgum.js +++ b/ads/gumgum.js @@ -35,7 +35,7 @@ export function gumgum(global, data) { slotId = parseInt(data.slot, 10), onLoad = function(type) { return function(evt) { - const ad = Object.assign({width: 0, height: 0}, evt.ad || {}), + const ad = {width: 0, height: 0, ...(evt.ad || {})}, identifier = ['GUMGUM', type, evt.id].join('_'); ctx.reportRenderedEntityIdentifier(identifier); ctx.renderStart({ diff --git a/ads/inabox/inabox-host.md b/ads/inabox/inabox-host.md index 24f950c3e6337..0adfe8bdffe99 100644 --- a/ads/inabox/inabox-host.md +++ b/ads/inabox/inabox-host.md @@ -78,6 +78,11 @@ Main workflow: 1. The ads tag creates an iframe, and set the response content to the iframe using `srcdoc`. +Note that this friendly iframe approach right now is in an experimental +stage. Put the following meta tag in the head of the ad HTML to opt-in +the experiment: +``. + ###### Security assurance In case that the AMPHTML ad is generated by a 3rd party, to ensure it's diff --git a/ads/inabox/position-observer.js b/ads/inabox/position-observer.js index 8f1a2334f5683..dcb6aff372d6c 100644 --- a/ads/inabox/position-observer.js +++ b/ads/inabox/position-observer.js @@ -136,7 +136,11 @@ export class PositionObserver { const parentWin = element.ownerDocument.defaultView; for ( let j = 0, tempWin = parentWin; - j < 10 && tempWin != this.win_ && tempWin != this.win_.top; + j < 10 && + // win can be null if the ad iframe is already destroyed + tempWin && + tempWin != this.win_ && + tempWin != this.win_.top; j++, tempWin = tempWin.parent ) { const parentFrameRect = layoutRectFromDomRect( diff --git a/ads/nativery.js b/ads/nativery.js new file mode 100644 index 0000000000000..1b40a80c2746d --- /dev/null +++ b/ads/nativery.js @@ -0,0 +1,45 @@ +/** + * Copyright 2018 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {validateData, writeScript} from '../3p/3p'; + +/** + * @param {!Window} global + * @param {!Object} data + */ +export function nativery(global, data) { + validateData(data, ['wid']); + const params = {...data}; + + // push the two object into the '_nativery' global + global._nativery = global._nativery || { + wid: data.wid, + referrer: data.referrer || global.context.referrer, + url: data.url || global.context.canonicalUrl, + viewId: global.context.pageViewId, + params, + }; + + // must add listener for resize + global.addEventListener('amp-widgetCreated', function(e) { + if (e && e.detail) { + global.context.requestResize(undefined, e.detail.height); + } + }); + + // load the nativery loader asynchronously + writeScript(global, `https://cdn.nativery.com/widget/js/natamp.js`); +} diff --git a/ads/nativery.md b/ads/nativery.md new file mode 100644 index 0000000000000..de69333e6a101 --- /dev/null +++ b/ads/nativery.md @@ -0,0 +1,36 @@ + + +# Nativery + +## Example + +### Basic + +```html + + +``` + +## Configuration + +For details on the configuration semantics, please contact the ad network or refer to their documentation. diff --git a/ads/readmo.js b/ads/readmo.js index 9e8b0cfde907e..12685b07313c2 100644 --- a/ads/readmo.js +++ b/ads/readmo.js @@ -29,7 +29,7 @@ export function readmo(global, data) { const {section, module, sponsoredByLabel, infinite, title, url} = data; - window.publisherUrl = url; + global.publisherUrl = url; (global.readmo = global.readmo || []).push({ section, @@ -41,21 +41,6 @@ export function readmo(global, data) { amp: true, }); - global.context.observeIntersection( - entries => { - entries.forEach(entry => { - if (global.Readmo) { - global.Readmo.onViewChange({ - intersectionRatio: entry.intersectionRatio, - }); - } - }); - }, - { - threshold: [0, 0.5, 1], - } - ); - loadScript(global, 'https://s.yimg.com/dy/ads/readmo.js', () => global.context.renderStart() ); diff --git a/ads/readmo.md b/ads/readmo.md index 1aee88f7c56fb..b8af4ee4c9513 100644 --- a/ads/readmo.md +++ b/ads/readmo.md @@ -28,7 +28,7 @@ ReadMo only requires a section code to run. Please work your account manager to height="400" type="readmo" layout="responsive" - data-url="https://yoursite.com" + data-url="https://yourdomain.com" data-infinite="true" data-section="1234567" > diff --git a/ads/revjet.js b/ads/revjet.js index 417a8e8c19c5a..50af0213fc017 100644 --- a/ads/revjet.js +++ b/ads/revjet.js @@ -23,7 +23,7 @@ import {loadScript, validateData} from '../3p/3p'; export function revjet(global, data) { validateData(data, ['tag', 'key'], ['plc', 'opts', 'params']); - global._revjetData = Object.assign({}, data); + global._revjetData = {...data}; loadScript( global, diff --git a/ads/ssp.js b/ads/ssp.js new file mode 100644 index 0000000000000..3290f0698be43 --- /dev/null +++ b/ads/ssp.js @@ -0,0 +1,77 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {computeInMasterFrame, loadScript, validateData} from '../3p/3p'; + +/** + * @param {!Window} global + * @param {!Object} data + */ +export function ssp(global, data) { + // validate AMP input data- attributes + validateData(data, ['id', 'width', 'height', 'zoneid'], ['site']); + + // create parent element + const adWrapper = document.createElement('div'); + + adWrapper.id = data.id; + + // https://github.com/ampproject/amphtml/tree/master/ads#the-iframe-sandbox + global.document.getElementById('c').appendChild(adWrapper); + + // https://github.com/ampproject/amphtml/blob/master/3p/3p.js#L186 + computeInMasterFrame( + global, + 'ssp-load', + done => { + loadScript(global, 'https://ssp.imedia.cz/static/js/ssp.js', () => { + // Script will inject "sssp" object on Window + if (!global['sssp']) { + done(null); + + return; + } + + /** @type {{config: Function, getAds: Function}} */ + const ssp = global['sssp']; + + ssp.config({ + site: data.site || global.context.canonicalUrl, + }); + + ssp.getAds( + { + zoneId: data.zoneid, + id: data.id, + width: data.width, + height: data.height, + }, + { + requestErrorCallback: () => done(null), + AMPcallback: ads => done(ads), + } + ); + }); + }, + ads => { + if (ads && ads[0] && ads[0].type !== 'error') { + global.context.renderStart(); + } else { + global.context.noContentAvailable(); + } + } + ); +} diff --git a/ads/ssp.md b/ads/ssp.md new file mode 100644 index 0000000000000..84a17b13118df --- /dev/null +++ b/ads/ssp.md @@ -0,0 +1,44 @@ + + +# SSP + +## Example + +```html + + +``` + +## Configuration + +Required parameters: + +- `data-id` +- `data-width`: Width of position (must be same as width attribute) +- `data-width`: Height of position (must be same as height attribute) +- `data-zoneid`: Id of zone + +## Contact + +reklama-pozadavky@firma.seznam.cz diff --git a/ads/sulvo.js b/ads/sulvo.js new file mode 100644 index 0000000000000..7827f47ed7a61 --- /dev/null +++ b/ads/sulvo.js @@ -0,0 +1,25 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {loadScript} from '../3p/3p'; + +/** + * @param {!Window} global + * @param {!Object} data + */ +export function sulvo(global, data) { + global.sulvoAmpAdData = data; + loadScript(global, 'https://live.demand.supply/up.amp.js'); +} diff --git a/ads/sulvo.md b/ads/sulvo.md new file mode 100644 index 0000000000000..adbc048e94714 --- /dev/null +++ b/ads/sulvo.md @@ -0,0 +1,52 @@ + + +# Sulvo + +## Example + +### Regular ad + +```html + +``` + +### Sticky ad + +```html + + + +``` + +## Configuration + +For further information, please contact [Sulvo](https://sulvo.com/). + +### Required parameters + +- `data-ad`: Ad ID provided by Sulvo. diff --git a/ads/vdoai.js b/ads/vdoai.js new file mode 100644 index 0000000000000..3535b62e879f2 --- /dev/null +++ b/ads/vdoai.js @@ -0,0 +1,29 @@ +/** + * Copyright 2020 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {loadScript} from '../3p/3p'; +/** + * @param {!Window} global + * @param {!Object} data + */ +export function vdoai(global, data) { + /*eslint "google-camelcase/google-camelcase": 0*/ + global.vdo_ai_ = { + unitData: data['unitid'], + unitTagname: data['tagname'], + }; + loadScript(global, 'https://a.vdo.ai/core/dependencies_amp/remote.js'); +} diff --git a/ads/vdoai.md b/ads/vdoai.md new file mode 100644 index 0000000000000..5c86b26792e75 --- /dev/null +++ b/ads/vdoai.md @@ -0,0 +1,38 @@ + + +# VDO.AI + +## Example + +```html + + +``` + +## Configuration + +Supported parameters: + +- `data-unitid` +- `data-tagname` diff --git a/ads/yahoonativeads.js b/ads/yahoonativeads.js index 0ea90a7f0e7df..4d2c284d9ec07 100644 --- a/ads/yahoonativeads.js +++ b/ads/yahoonativeads.js @@ -29,21 +29,6 @@ export function yahoonativeads(global, data) { global.publisherUrl = data.url; global.amp = true; - global.context.observeIntersection( - entries => { - entries.forEach(entry => { - if (global.Native) { - global.Native.onViewChange({ - intersectionRatio: entry.intersectionRatio, - }); - } - }); - }, - { - threshold: [0, 0.5, 1], - } - ); - loadScript(global, 'https://s.yimg.com/dy/ads/native.js', () => global.context.renderStart() ); diff --git a/ads/zucks.js b/ads/zucks.js index 0f1f3c154b4da..c5d558461942e 100644 --- a/ads/zucks.js +++ b/ads/zucks.js @@ -29,8 +29,7 @@ export function zucks(global, data) { const d = global.document.createElement('ins'); d.id = elementId; - const container = document.getElementById('c'); - container.appendChild(d); + global.document.getElementById('c').appendChild(d); if (data['zoeMultiAd'] !== 'true') { (global.gZgokZoeQueue = global.gZgokZoeQueue || []).push({frameId}); @@ -42,7 +41,9 @@ export function zucks(global, data) { }); }); } else if (data['adtype'] === 'native') { - loadScript(global, `https://j.zucks.net.zimg.jp/n?f=${data['frameId']}`); + const s = global.document.createElement('script'); + s.src = `https://j.zucks.net.zimg.jp/n?f=${data['frameId']}`; + global.document.getElementById('c').appendChild(s); } else { writeScript(global, `https://j.zucks.net.zimg.jp/j?f=${data['frameId']}`); } diff --git a/babel.config.js b/babel.config.js index e49b55c83ec00..279389c5e583f 100644 --- a/babel.config.js +++ b/babel.config.js @@ -29,7 +29,8 @@ const minimist = require('minimist'); const {isTravisBuild} = require('./build-system/common/travis'); const argv = minimist(process.argv.slice(2)); -const isDist = argv._.includes('dist'); +const isClosureCompiler = + argv._.includes('dist') || argv._.includes('check-types'); const {esm} = argv; const noModuleTarget = { 'browsers': isTravisBuild() @@ -40,9 +41,9 @@ const noModuleTarget = { // eslint-disable-next-line local/no-module-exports module.exports = function(api) { api.cache(true); - // `dist` builds do not use any of the default settings below until its + // Closure Compiler builds do not use any of the default settings below until its // an esm build. (Both Multipass and Singlepass) - if (isDist && !esm) { + if (isClosureCompiler && !esm) { return {}; } return { @@ -57,7 +58,7 @@ module.exports = function(api) { : [ '@babel/preset-env', { - 'modules': isDist ? false : 'commonjs', + 'modules': isClosureCompiler ? false : 'commonjs', 'loose': true, 'targets': noModuleTarget, }, diff --git a/build-system/.eslintrc b/build-system/.eslintrc index 02be31348f713..29a41b9f6ec54 100644 --- a/build-system/.eslintrc +++ b/build-system/.eslintrc @@ -20,10 +20,12 @@ }, "rules": { "local/no-array-destructuring": 0, + "local/no-destructure-assignment-params": 0, "local/no-export-side-effect": 0, "local/no-for-of-statement": 0, "local/no-has-own-property-method": 0, "local/no-module-exports": 0, + "local/no-rest": 0, "local/no-spread": 0, "require-jsdoc": 0 } diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/index.js b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/index.js index c7b88407d5907..c36d286d39397 100644 --- a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/index.js +++ b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/index.js @@ -51,10 +51,10 @@ module.exports = function(babel) { /** * @param {!NodePath} path - * @param {boolean} assertion * @param {string|undefined} type + * @param {boolean} assertion */ - function eliminate(path, assertion, type) { + function eliminate(path, type, assertion) { const argument = path.get('arguments.0'); if (!argument) { if (assertion) { @@ -94,20 +94,16 @@ module.exports = function(babel) { } } - path.replaceWith(t.parenthesizedExpression(arg)); - if (type) { + path.replaceWith(t.parenthesizedExpression(arg)); // If it starts with a capital, make the type non-nullable. if (/^[A-Z]/.test(type)) { type = '!' + type; } // Add a cast annotation to fix type. path.addComment('leading', `* @type {${type}} `); - } - - const {parenthesized} = path.node.extra || {}; - if (parenthesized) { - path.replaceWith(t.parenthesizedExpression(path.node)); + } else if (!assertion) { + path.replaceWith(t.parenthesizedExpression(arg)); } } @@ -117,7 +113,7 @@ module.exports = function(babel) { const callee = path.get('callee'); if (callee.isIdentifier({name: 'devAssert'})) { - return eliminate(path, true, ''); + return eliminate(path, '', /* assertion */ true); } const isMemberAndCallExpression = @@ -144,7 +140,11 @@ module.exports = function(babel) { } const method = prop.node.name; - eliminate(path, method.startsWith('assert'), typeMap[method]); + eliminate( + path, + typeMap[method], + /* assertion */ method.startsWith('assert') + ); }, }, }; diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-dev-assert/input.js b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-user-assert/input.js similarity index 100% rename from build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-dev-assert/input.js rename to build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-user-assert/input.js diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-dev-assert/options.json b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-user-assert/options.json similarity index 100% rename from build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-dev-assert/options.json rename to build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-user-assert/options.json diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-dev-assert/output.js b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-user-assert/output.js similarity index 100% rename from build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-dev-assert/output.js rename to build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-user-assert/output.js diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-userAssert/output.js b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-userAssert/output.js index 154ca3b5450b9..683a7e7ebca20 100644 --- a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-userAssert/output.js +++ b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/no-transform-userAssert/output.js @@ -14,7 +14,7 @@ * limitations under the License. */ userAssert(1 + 1); -userAssert((2 + 2)); +userAssert(dev().assert(2 + 2)); userAssert(); let result = userAssert(dev(), 'hello', 'world'); let result2 = userAssert(); diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-dev-assert/input.js b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-dev-assert/input.js index bb509c0eab99d..a51e7d50922f9 100644 --- a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-dev-assert/input.js +++ b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-dev-assert/input.js @@ -15,4 +15,4 @@ */ dev().assert(1 + 1); dev().assert(dev().assert(2 + 2)); -let result = dev().assert(dev(), 'hello', 'world'); +let result = dev().assert(foo, 'hello', 'world'); diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-dev-assert/output.js b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-dev-assert/output.js index 6169818473b88..a51e7d50922f9 100644 --- a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-dev-assert/output.js +++ b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-dev-assert/output.js @@ -13,6 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -(1 + 1); -((2 + 2)); -let result = (dev()); +dev().assert(1 + 1); +dev().assert(dev().assert(2 + 2)); +let result = dev().assert(foo, 'hello', 'world'); diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-devAssert/input.js b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-devAssert/input.js index 2a55df63d3370..5b9db4a5faad9 100644 --- a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-devAssert/input.js +++ b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-devAssert/input.js @@ -15,4 +15,4 @@ */ devAssert(1 + 1); devAssert(dev().assert(2 + 2)); -let result = devAssert(dev(), 'hello', 'world'); +let result = devAssert(foo, 'hello', 'world'); diff --git a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-devAssert/output.js b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-devAssert/output.js index 83995bbdc16f4..5b9db4a5faad9 100644 --- a/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-devAssert/output.js +++ b/build-system/babel-plugins/babel-plugin-transform-amp-asserts/test/fixtures/transform-assertions/transform-devAssert/output.js @@ -13,6 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -(1 + 1); -((2 + 2)); -let result = (dev()); +devAssert(1 + 1); +devAssert(dev().assert(2 + 2)); +let result = devAssert(foo, 'hello', 'world'); diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/index.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/index.js new file mode 100644 index 0000000000000..1eed40daea5e5 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/index.js @@ -0,0 +1,89 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module.exports = function(babel) { + const {types: t} = babel; + + function cloneDeepWithoutLoc(node) { + const str = JSON.stringify(node); + return JSON.parse(str, (key, value) => { + return key === 'loc' ? undefined : value; + }); + } + + function declarator(path, parentPath) { + const init = parentPath.get('init'); + let from = init.node; + if (!init.isPure()) { + from = path.scope.generateUidIdentifierBasedOnNode(init.node); + parentPath.insertBefore( + t.variableDeclarator(from, cloneDeepWithoutLoc(init.node)) + ); + } + + const properties = path.get('properties'); + for (const prop of properties) { + const {key, value, computed} = prop.node; + const member = t.memberExpression( + t.cloneWithoutLoc(from), + key, + computed || !t.isIdentifier(key) + ); + let expression = member; + let newValue = value; + if (t.isAssignmentPattern(value)) { + newValue = t.identifier(value.left.name); + expression = t.conditionalExpression( + t.binaryExpression('===', member, path.scope.buildUndefinedNode()), + value.right, + member + ); + } + const declarator = t.variableDeclarator(newValue, expression); + parentPath.insertBefore(declarator); + } + // NOTE: this is a hack to remove the original path as `parentPath.remove()` causes + // an unexplained error. + path.replaceWith(path.scope.generateUidIdentifier('foo')); + // We try to eliminate any side effects since the original + // initializer might have had some (method call, etc.); + parentPath.get('init').replaceWith(path.scope.buildUndefinedNode()); + } + + return { + name: 'simple-object-destructure', + + pre() { + this.file.opts.generatorOpts.retainLines = true; + }, + + visitor: { + ObjectPattern(path) { + // NOTE: We don't transform destructure operation in params as this causes + // type parameter mismatch errors. + + const {parentPath} = path; + if (parentPath.isObjectProperty()) { + throw path.buildCodeFrameError('encountered deep object destructure'); + } + + if (parentPath.isVariableDeclarator()) { + return declarator(path, parentPath); + } + }, + }, + }; +}; diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/input.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/input.js new file mode 100644 index 0000000000000..113c5892f9e5a --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/input.js @@ -0,0 +1,17 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const [a, ...b] = [1, 2, 3, 4, 5]; diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/options.json b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/options.json new file mode 100644 index 0000000000000..800c09891c3d8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["../../../../../babel-plugin-transform-simple-object-destructure"] +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/output.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/output.js new file mode 100644 index 0000000000000..113c5892f9e5a --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/array-destructure/output.js @@ -0,0 +1,17 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const [a, ...b] = [1, 2, 3, 4, 5]; diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/input.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/input.js new file mode 100644 index 0000000000000..213f1662ecda4 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/input.js @@ -0,0 +1,22 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function func({head}) { + console.log(head); +} + +func(document); +func({head: document.head}); diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/options.json b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/options.json new file mode 100644 index 0000000000000..800c09891c3d8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["../../../../../babel-plugin-transform-simple-object-destructure"] +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/output.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/output.js new file mode 100644 index 0000000000000..3f469ece3bb61 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/no-transform/param-destructure/output.js @@ -0,0 +1,22 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function func({ head }) { + console.log(head); +} + +func(document); +func({ head: document.head }); diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/input.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/input.js new file mode 100644 index 0000000000000..a607dd25a570c --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/input.js @@ -0,0 +1,23 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function func() { + const { + [axisName]: value, + [axisName + 'Min']: min = 0, + [axisName + 'Max']: max = Math.PI * 2, + } = args; +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/options.json b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/options.json new file mode 100644 index 0000000000000..800c09891c3d8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["../../../../../babel-plugin-transform-simple-object-destructure"] +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/output.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/output.js new file mode 100644 index 0000000000000..b09cc03f58350 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/computed-keys/output.js @@ -0,0 +1,23 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function func() { + const _args = args, + value = _args[axisName],min = _args[ + axisName + 'Min'] === void 0 ? 0 : _args[axisName + 'Min'],max = _args[ + axisName + 'Max'] === void 0 ? Math.PI * 2 : _args[axisName + 'Max'],_foo = void 0; + +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/input.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/input.js new file mode 100644 index 0000000000000..c2e3cd310f28a --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/input.js @@ -0,0 +1,19 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function func() { + let {x = 5, y, z = document.head} = get(); +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/options.json b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/options.json new file mode 100644 index 0000000000000..800c09891c3d8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["../../../../../babel-plugin-transform-simple-object-destructure"] +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/output.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/output.js new file mode 100644 index 0000000000000..648f97e9d8eb8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/default-values/output.js @@ -0,0 +1,19 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function func() { + let _get = get(),x = _get.x === void 0 ? 5 : _get.x,y = _get.y,z = _get.z === void 0 ? document.head : _get.z,_foo = void 0; +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/input.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/input.js new file mode 100644 index 0000000000000..a7ba33f2ea206 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/input.js @@ -0,0 +1,27 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function string() { + const obj = {}; + let {'foo': bar} = obj; + let {'foo': baz} = get(); +} + +function number() { + const obj = {}; + let {0: bar} = obj; + let {0: baz} = get(); +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/options.json b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/options.json new file mode 100644 index 0000000000000..800c09891c3d8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["../../../../../babel-plugin-transform-simple-object-destructure"] +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/output.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/output.js new file mode 100644 index 0000000000000..92c8bf5835a29 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/non-identifier-keys/output.js @@ -0,0 +1,27 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function string() { + const obj = {}; + let bar = obj['foo'],_foo = void 0; + let _get = get(),baz = _get['foo'],_foo2 = void 0; +} + +function number() { + const obj = {}; + let bar = obj[0],_foo3 = void 0; + let _get2 = get(),baz = _get2[0],_foo4 = void 0; +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/input.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/input.js new file mode 100644 index 0000000000000..86f794d5f0274 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/input.js @@ -0,0 +1,36 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const {head: h, body: b} = document; + +const {x: myX} = get(); + +function func() { + const {head: h, body: b} = document; + let {x: myX, y: myY, z: myZ} = get(); + myX = 3; + myY = 4; + myZ = 5; + console.log(document); + console.log(h); + console.log(b); + console.log(myX + myY + myZ); +} + +console.log(document); +console.log(h); +console.log(b); +console.log(myX); diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/options.json b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/options.json new file mode 100644 index 0000000000000..800c09891c3d8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["../../../../../babel-plugin-transform-simple-object-destructure"] +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/output.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/output.js new file mode 100644 index 0000000000000..2ec1244fde4e8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations-rename/output.js @@ -0,0 +1,36 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const _document = document,h = _document.head,b = _document.body,_foo = void 0; + +const _get = get(),myX = _get.x,_foo2 = void 0; + +function func() { + const _document2 = document,h = _document2.head,b = _document2.body,_foo3 = void 0; + let _get2 = get(),myX = _get2.x,myY = _get2.y,myZ = _get2.z,_foo4 = void 0; + myX = 3; + myY = 4; + myZ = 5; + console.log(document); + console.log(h); + console.log(b); + console.log(myX + myY + myZ); +} + +console.log(document); +console.log(h); +console.log(b); +console.log(myX); diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/input.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/input.js new file mode 100644 index 0000000000000..2b31839ad13a4 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/input.js @@ -0,0 +1,36 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const {head, body} = document; + +const {x} = get(); + +function func() { + const {head, body} = document; + let {x, y, z} = get(); + x = 3; + y = 4; + z = 5; + console.log(document); + console.log(head); + console.log(body); + console.log(x + y + z); +} + +console.log(document); +console.log(head); +console.log(body); +console.log(x); diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/options.json b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/options.json new file mode 100644 index 0000000000000..800c09891c3d8 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["../../../../../babel-plugin-transform-simple-object-destructure"] +} diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/output.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/output.js new file mode 100644 index 0000000000000..49d5d568bf8d9 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/fixtures/transform/variable-declarations/output.js @@ -0,0 +1,36 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const _document = document,head = _document.head,body = _document.body,_foo = void 0; + +const _get = get(),x = _get.x,_foo2 = void 0; + +function func() { + const _document2 = document,head = _document2.head,body = _document2.body,_foo3 = void 0; + let _get2 = get(),x = _get2.x,y = _get2.y,z = _get2.z,_foo4 = void 0; + x = 3; + y = 4; + z = 5; + console.log(document); + console.log(head); + console.log(body); + console.log(x + y + z); +} + +console.log(document); +console.log(head); +console.log(body); +console.log(x); diff --git a/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/index.js b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/index.js new file mode 100644 index 0000000000000..44564fa07fec0 --- /dev/null +++ b/build-system/babel-plugins/babel-plugin-transform-simple-object-destructure/test/index.js @@ -0,0 +1,19 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const runner = require('@babel/helper-plugin-test-runner').default; + +runner(__dirname); diff --git a/build-system/common/exec.js b/build-system/common/exec.js index 025fbd5d5a615..94c3b43e6cb9f 100644 --- a/build-system/common/exec.js +++ b/build-system/common/exec.js @@ -31,7 +31,7 @@ const shellCmd = process.platform == 'win32' ? 'cmd' : '/bin/bash'; * @return {!Object} */ function spawnProcess(cmd, options) { - return childProcess.spawnSync(cmd, Object.assign({shell: shellCmd}, options)); + return childProcess.spawnSync(cmd, {shell: shellCmd, ...options}); } /** @@ -55,7 +55,7 @@ function exec(cmd, options) { * @return {!Object} */ function execScriptAsync(script, options) { - return childProcess.spawn(script, Object.assign({shell: shellCmd}, options)); + return childProcess.spawn(script, {shell: shellCmd, ...options}); } /** diff --git a/build-system/compile/build.conf.js b/build-system/compile/build.conf.js index 3dbc157c30135..a260f4db65ba2 100644 --- a/build-system/compile/build.conf.js +++ b/build-system/compile/build.conf.js @@ -27,7 +27,6 @@ const defaultPlugins = [ localPlugin('transform-amp-extension-call'), localPlugin('transform-html-template'), localPlugin('transform-version-call'), - getJsonConfigurationPlugin(), getReplacePlugin(), ]; @@ -91,17 +90,19 @@ function getReplacePlugin() { } }); - // default each backup experiment constant to false as well - Object.keys(experimentsConstantBackup).forEach(experimentDefine => { + // default each backup experiment constant to the customized value + for (const [experimentDefine, value] of Object.entries( + experimentsConstantBackup + )) { function flagExists(element) { return element['identifierName'] === experimentDefine; } // only add default replacement if it already doesn't exist in array if (experimentDefine && !replacements.some(flagExists)) { - replacements.push(createReplacement(experimentDefine, false)); + replacements.push(createReplacement(experimentDefine, !!value)); } - }); + } return ['minify-replace', {replacements}]; } @@ -119,7 +120,7 @@ function getJsonConfigurationPlugin() { * @param {!Object} buildFlags * @return {!Array>} */ -function plugins({isEsmBuild, isForTesting, isSinglePass}) { +function plugins({isEsmBuild, isForTesting, isSinglePass, isChecktypes}) { const applied = [...defaultPlugins]; // TODO(erwinm): This is temporary until we remove the assert/log removals // from the java transformation to the babel transformation. @@ -134,7 +135,14 @@ function plugins({isEsmBuild, isForTesting, isSinglePass}) { if (isEsmBuild) { applied.push(['filter-imports', {imports: esmRemovedImports}]); } - if (!isForTesting) { + if (isChecktypes) { + applied.push(localPlugin('transform-simple-object-destructure')); + } else { + // This triggers some conformance errors such as `use tryParseJson` during + // type check phase so we omit it from the default plugins. + applied.push(getJsonConfigurationPlugin()); + } + if (!(isForTesting || isChecktypes)) { applied.push( localPlugin('amp-mode-transformer'), localPlugin('is_dev-constant-transformer') diff --git a/build-system/compile/bundles.config.js b/build-system/compile/bundles.config.js index 5bf6105787067..1eb94f4275906 100644 --- a/build-system/compile/bundles.config.js +++ b/build-system/compile/bundles.config.js @@ -489,7 +489,7 @@ exports.extensionBundles = [ }, { name: 'amp-date-display', - version: '0.1', + version: ['0.1', '0.2'], latestVersion: '0.1', type: TYPES.MISC, }, @@ -637,6 +637,20 @@ exports.extensionBundles = [ latestVersion: '0.1', type: TYPES.MEDIA, }, + { + name: 'amp-inline-gallery', + version: '0.1', + latestVersion: '0.1', + options: { + hasCss: true, + cssBinaries: [ + 'amp-inline-gallery', + 'amp-inline-gallery-pagination', + 'amp-inline-gallery-thumbnails', + ], + }, + type: TYPES.MISC, + }, { name: 'amp-inputmask', version: '0.1', @@ -739,7 +753,7 @@ exports.extensionBundles = [ }, { name: 'amp-next-page', - version: '0.1', + version: ['0.1', '1.0'], latestVersion: '0.1', options: {hasCss: true}, type: TYPES.MISC, @@ -782,6 +796,12 @@ exports.extensionBundles = [ latestVersion: '0.1', type: TYPES.MEDIA, }, + { + name: 'amp-redbull-player', + version: '0.1', + latestVersion: '0.1', + type: TYPES.MEDIA, + }, { name: 'amp-reddit', version: '0.1', @@ -879,16 +899,17 @@ exports.extensionBundles = [ hasCss: true, cssBinaries: [ 'amp-story-bookend', - 'amp-story-tooltip', 'amp-story-consent', 'amp-story-draggable-drawer-header', 'amp-story-hint', - 'amp-story-unsupported-browser-layer', - 'amp-story-viewport-warning-layer', 'amp-story-info-dialog', + 'amp-story-quiz', 'amp-story-share', 'amp-story-share-menu', 'amp-story-system-layer', + 'amp-story-tooltip', + 'amp-story-unsupported-browser-layer', + 'amp-story-viewport-warning-layer', ], }, type: TYPES.MISC, diff --git a/build-system/compile/check-for-unknown-deps.js b/build-system/compile/check-for-unknown-deps.js index b46b5422b7aa7..3f2e743d1a574 100644 --- a/build-system/compile/check-for-unknown-deps.js +++ b/build-system/compile/check-for-unknown-deps.js @@ -17,7 +17,7 @@ const log = require('fancy-log'); const through = require('through2'); -const {red, cyan} = require('ansi-colors'); +const {red, cyan, yellow} = require('ansi-colors'); /** * Searches for the identifier "$$module$", which Closure uses to uniquely @@ -44,6 +44,7 @@ exports.checkForUnknownDeps = function() { red('Error:'), `Unknown dependency ${cyan(match[0])} found in ${cyan(file.relative)}` ); + log(yellow(contents)); const err = new Error('Compilation failed due to unknown dependency'); err.showStack = false; cb(err, file); diff --git a/build-system/compile/compile.js b/build-system/compile/compile.js index 146273bec8542..8beafb5cb516b 100644 --- a/build-system/compile/compile.js +++ b/build-system/compile/compile.js @@ -139,6 +139,7 @@ function compile( 'third_party/web-animations-externs/web_animations.js', 'third_party/moment/moment.extern.js', 'third_party/react-externs/externs.js', + 'build-system/externs/preact.extern.js', ]; const define = [`VERSION=${internalRuntimeVersion}`]; if (argv.pseudo_names) { @@ -270,9 +271,9 @@ function compile( compilation_level: options.compilationLevel || 'SIMPLE_OPTIMIZATIONS', // Turns on more optimizations. assume_function_wrapper: true, - // Transpile from ES6 to ES5 if not running with `--esm` - // otherwise transpilation is done by Babel - language_in: argv.esm ? 'ECMASCRIPT_2017' : 'ECMASCRIPT6', + language_in: 'ECMASCRIPT_2018', + // Do not transpile down to ES5 if running with `--esm`, since we do + // limited transpilation in Babel. language_out: argv.esm ? 'NO_TRANSPILE' : 'ECMASCRIPT5', // We do not use the polyfills provided by closure compiler. // If you need a polyfill. Manually include them in the @@ -288,6 +289,7 @@ function compile( ], entry_point: entryModuleFilenames, module_resolution: 'NODE', + package_json_entry_names: 'module,main', process_common_js_modules: true, // This strips all files from the input set that aren't explicitly // required. @@ -323,17 +325,14 @@ function compile( // it won't do strict type checking if its whitespace only. compilerOptions.define.push('TYPECHECK_ONLY=true'); compilerOptions.jscomp_error.push( + 'accessControls', 'conformanceViolations', 'checkTypes', 'const', 'constantProperty', 'globalThis' ); - compilerOptions.jscomp_off.push( - 'accessControls', - 'moduleLoad', - 'unknownDefines' - ); + compilerOptions.jscomp_off.push('moduleLoad', 'unknownDefines'); compilerOptions.conformance_configs = 'build-system/test-configs/conformance-config.textproto'; } else { @@ -345,7 +344,7 @@ function compile( delete compilerOptions.define; } - if (!argv.single_pass && !options.typeCheckOnly) { + if (!argv.single_pass) { compilerOptions.js_module_root.push(SRC_TEMP_DIR); } @@ -365,9 +364,13 @@ function compile( } }); + const gulpSrcs = !argv.single_pass ? convertPathsToTmpRoot(srcs) : srcs; + const gulpBase = !argv.single_pass ? SRC_TEMP_DIR : '.'; + if (options.typeCheckOnly) { return gulp - .src(srcs, {base: '.'}) + .src(gulpSrcs, {base: gulpBase}) + .pipe(sourcemaps.init({loadMaps: true})) .pipe(gulpClosureCompile(compilerOptionsArray, checkTypesNailgunPort)) .on('error', err => { handleTypeCheckError(); @@ -376,8 +379,6 @@ function compile( .pipe(nop()) .on('end', resolve); } else { - const gulpSrcs = argv.single_pass ? srcs : convertPathsToTmpRoot(srcs); - const gulpBase = argv.single_pass ? '.' : SRC_TEMP_DIR; timeInfo.startTime = Date.now(); return gulp .src(gulpSrcs, {base: gulpBase}) diff --git a/build-system/compile/single-pass.js b/build-system/compile/single-pass.js index d08b830d2ddca..72f942d4f727b 100644 --- a/build-system/compile/single-pass.js +++ b/build-system/compile/single-pass.js @@ -28,8 +28,7 @@ const log = require('fancy-log'); const MagicString = require('magic-string'); const minimist = require('minimist'); const path = require('path'); -const Promise = require('bluebird'); -const relativePath = require('path').relative; +const pkgUp = require('pkg-up'); const rename = require('gulp-rename'); const resorcery = require('@jridgewell/resorcery'); const sourcemaps = require('gulp-sourcemaps'); @@ -112,12 +111,13 @@ exports.getFlags = function(config) { // accessing the symbol, we remedy this by attaching all public exports // to `_` and everything imported across modules is is accessed through `_`. rename_prefix_namespace: '_', - language_in: config.esm ? 'ECMASCRIPT_2017' : 'ECMASCRIPT6', + language_in: 'ECMASCRIPT_2018', language_out: config.esm ? 'NO_TRANSPILE' : config.language_out || 'ECMASCRIPT5', chunk_output_path_prefix: config.writeTo || 'out/', module_resolution: 'NODE', + package_json_entry_names: 'module,main', process_common_js_modules: true, externs: config.externs, define: config.define, @@ -165,7 +165,11 @@ exports.getBundleFlags = function(g) { Object.keys(g.packages) .sort() .forEach(function(pkg) { - srcs.push(pkg); + g.bundles[mainBundle].modules.push(pkg); + fs.outputFileSync( + `${g.tmp}/${pkg}`, + JSON.stringify(JSON.parse(readFile(pkg)), null, 4) + ); }); // Build up the weird flag structure that closure compiler calls @@ -264,7 +268,6 @@ exports.getBundleFlags = function(g) { throw new Error('Expect to build more than one bundle.'); } }); - flagsArray.push('--js_module_root', `${g.tmp}/node_modules/`); flagsArray.push('--js_module_root', `${g.tmp}/`); return flagsArray; }; @@ -315,6 +318,7 @@ exports.getGraph = function(entryModules, config) { deps: true, detectGlobals: false, fast: true, + browserField: 'module', }) // The second stage are transforms that closure compiler supports // directly and which we don't want to apply during deps finding. @@ -343,14 +347,21 @@ exports.getGraph = function(entryModules, config) { }) .forEach(function(row) { const id = unifyPath( - exports.maybeAddDotJs(relativePath(process.cwd(), row.id)) + exports.maybeAddDotJs(path.relative(process.cwd(), row.id)) ); topo.addNode(id, id); - const deps = (edges[id] = Object.keys(row.deps) + const deps = Object.keys(row.deps) .sort() - .map(function(dep) { - return unifyPath(relativePath(process.cwd(), row.deps[dep])); - })); + .map(dep => { + dep = unifyPath(path.relative(process.cwd(), row.deps[dep])); + if (dep.startsWith('node_modules/')) { + const pkgJson = pkgUp.sync({cwd: path.dirname(dep)}); + const jsonId = unifyPath(path.relative(process.cwd(), pkgJson)); + graph.packages[jsonId] = true; + } + return dep; + }); + edges[id] = deps; graph.deps[id] = deps; if (row.entry) { graph.depOf[id] = {}; diff --git a/build-system/compile/sources.js b/build-system/compile/sources.js index d9ebaf3559051..cc9f758f18910 100644 --- a/build-system/compile/sources.js +++ b/build-system/compile/sources.js @@ -39,12 +39,22 @@ const COMMON_GLOBS = [ 'third_party/timeagojs/**/*.js', 'third_party/vega/**/*.js', 'third_party/webcomponentsjs/ShadowCSS.js', + 'node_modules/dompurify/package.json', 'node_modules/dompurify/dist/purify.es.js', + 'node_modules/promise-pjs/package.json', 'node_modules/promise-pjs/promise.mjs', + 'node_modules/web-animations-js/package.json', 'node_modules/web-animations-js/web-animations.install.js', + 'node_modules/web-activities/package.json', 'node_modules/web-activities/activity-ports.js', + 'node_modules/@ampproject/animations/package.json', 'node_modules/@ampproject/animations/dist/animations.mjs', + 'node_modules/@ampproject/worker-dom/package.json', 'node_modules/@ampproject/worker-dom/dist/amp/main.mjs', + 'node_modules/preact/package.json', + 'node_modules/preact/dist/*.js', + 'node_modules/preact/hooks/package.json', + 'node_modules/preact/hooks/dist/*.js', ]; /** @@ -115,8 +125,6 @@ const CLOSURE_SRC_GLOBS = [ 'extensions/amp-geo/**/*.js', // Needed for AmpViewerAssistanceService 'extensions/amp-viewer-assistance/**/*.js', - // Needed for AmpViewerIntegrationVariableService - 'extensions/amp-viewer-integration/**/*.js', // Needed for amp-smartlinks dep on amp-skimlinks 'extensions/amp-skimlinks/0.1/**/*.js', 'src/*.js', diff --git a/build-system/eslint-rules/no-destructure-assignment-params.js b/build-system/eslint-rules/no-destructure-assignment-params.js new file mode 100644 index 0000000000000..4b2101faadc73 --- /dev/null +++ b/build-system/eslint-rules/no-destructure-assignment-params.js @@ -0,0 +1,29 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module.exports = function(context) { + return { + [':function > ObjectPattern']: function(node) { + context.report({ + node, + message: + 'Do not use Object Destructuring Assignment in parameters. ' + + 'We will allow it once https://github.com/google/' + + 'closure-compiler/issues/3500 is resolved.', + }); + }, + }; +}; diff --git a/build-system/eslint-rules/no-import.js b/build-system/eslint-rules/no-import.js index e694330aaa8df..daf26d4640bd9 100644 --- a/build-system/eslint-rules/no-import.js +++ b/build-system/eslint-rules/no-import.js @@ -14,19 +14,41 @@ * limitations under the License. */ 'use strict'; -const imports = ['sinon']; + +const imports = [ + {import: 'sinon', message: 'Importing sinon is forbidden'}, + { + import: 'preact', + message: + "Please import preact from 'src/preact'. This gives us type safety.", + }, + { + import: 'preact/hooks', + message: + "Please import preact/hooks from 'src/preact'. This gives us type safety.", + }, +]; + module.exports = function(context) { return { ImportDeclaration(node) { - const comments = context.getCommentsBefore(node); + const comments = context.getCommentsBefore(node.source); const ok = comments.some(comment => comment.value === 'OK'); if (ok) { return; } const name = node.source.value; - if (imports.includes(name)) { - context.report({node, message: `Importing ${name} is forbidden.`}); + + for (const forbidden of imports) { + if (name !== forbidden.import) { + continue; + } + + context.report({ + node, + message: forbidden.message, + }); } }, }; diff --git a/build-system/eslint-rules/no-rest.js b/build-system/eslint-rules/no-rest.js new file mode 100644 index 0000000000000..5da171b23043c --- /dev/null +++ b/build-system/eslint-rules/no-rest.js @@ -0,0 +1,47 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +// Forbids use of Rest elements when they require an iterator polyfill, or +// there's no clear benefit. +// +// Good: +// ``` +// function foo(...args) {} +// ``` +// +// Bad: +// ``` +// const [...rest] = [1, 2, 3]; +// const {...rest} = {foo: 1}; +// ``` +module.exports = function(context) { + return { + 'ArrayPattern > RestElement': function(node) { + context.report({ + node, + message: 'Collecting elements using a rest element is not allowed.', + }); + }, + + 'ObjectPattern > RestElement, ExperimentalRestProperty': function(node) { + context.report({ + node, + message: 'Collecting props using a rest property is not allowed.', + }); + }, + }; +}; diff --git a/build-system/eslint-rules/no-spread.js b/build-system/eslint-rules/no-spread.js index d0e672d722652..f67f36f600d18 100644 --- a/build-system/eslint-rules/no-spread.js +++ b/build-system/eslint-rules/no-spread.js @@ -15,10 +15,26 @@ */ 'use strict'; +// Forbids use of Spread elements when they require an iterator polyfill +// +// Good: +// ``` +// const obj = {foo: 1, ...obj}; +// ``` +// +// Bad: +// ``` +// const args = [1, 2, 3, ...array]; +// bar(...args); +// ``` module.exports = function(context) { return { - SpreadElement: function(node) { - context.report({node, message: 'No spread element allowed.'}); + 'ArrayExpression > SpreadElement': function(node) { + context.report({node, message: 'Iterator spreading is not allowed.'}); + }, + + 'CallExpression > SpreadElement': function(node) { + context.report({node, message: 'Iterator spreading is not allowed.'}); }, }; }; diff --git a/build-system/eslint-rules/prefer-spread-props.js b/build-system/eslint-rules/prefer-spread-props.js new file mode 100644 index 0000000000000..d83753179eec6 --- /dev/null +++ b/build-system/eslint-rules/prefer-spread-props.js @@ -0,0 +1,72 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +// This warns when using Object.assign where an object spread is better. Note +// that using Object.assign to mutate an already existing object is still +// allowed. +// +// Good: +// ``` +// const foo = {...obj}; +// const bar = {foo: 1, ...obj}; +// const baz = Object.assign(someObject, obj); +// ``` +// +// Bad: +// ``` +// const foo = Object.assign({}, obj); +// const bar = Object.assign({foo: 1}, obj); +// ``` +module.exports = { + meta: { + fixable: 'code', + }, + + create(context) { + const sourceCode = context.getSourceCode(); + + return { + 'CallExpression[callee.object.name="Object"][callee.property.name="assign"]': function( + node + ) { + const args = node.arguments; + if (args.length <= 1) { + return; + } + + const first = args[0]; + if (first.type !== 'ObjectExpression') { + return; + } + + context.report({ + node, + message: 'Prefer using object literals with spread property syntax', + + fix(fixer) { + const texts = args.map(arg => `...${sourceCode.getText(arg)}`); + if (first.properties.length === 0) { + texts.shift(); + } + + return fixer.replaceText(node, `({${texts.join(',')}})`); + }, + }); + }, + }; + }, +}; diff --git a/build-system/eslint-rules/prefer-unnested-spread-objects.js b/build-system/eslint-rules/prefer-unnested-spread-objects.js new file mode 100644 index 0000000000000..b073a6511ffd1 --- /dev/null +++ b/build-system/eslint-rules/prefer-unnested-spread-objects.js @@ -0,0 +1,88 @@ +/** + * Copyright 2019 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +// Disallows using an object spread on an inline object expression. Instead, +// the object expression's properties should be hoisted out inline with the +// rest of the outer object. +// +// Good: +// ``` +// const foo = { +// foo: 1, +// ...bar, +// baz: 2 +// }; +// ``` +// +// Bad: +// ``` +// const foo = { +// ...{ +// foo: 1, +// }, +// ...bar, +// ...{ +// baz: 2 +// }, +// }; +// ``` +module.exports = { + meta: { + fixable: 'code', + }, + + create(context) { + const sourceCode = context.getSourceCode(); + const spreadElement = + ':matches(ObjectExpression > ExperimentalSpreadProperty, ObjectExpression > SpreadElement)'; + + function findAfter(array, item) { + const index = array.indexOf(item); + return index < array.length - 1 ? array[index + 1] : null; + } + + return { + [`${spreadElement} > ObjectExpression`](node) { + context.report({ + node, + message: 'Nesting an object under an object spread is not useful', + + fix(fixer) { + const {properties, parent} = node; + const texts = properties.map(prop => sourceCode.getText(prop)); + + if (texts.length > 0) { + return fixer.replaceText(node.parent, texts.join(',')); + } + + const grandParent = parent.parent; + const next = findAfter(grandParent.properties, parent); + + if (next) { + return fixer.removeRange([parent.range[0], next.range[0] - 1]); + } + + return fixer.removeRange([ + parent.range[0], + grandParent.range[1] - 1, + ]); + }, + }); + }, + }; + }, +}; diff --git a/build-system/externs/amp.extern.js b/build-system/externs/amp.extern.js index d15f251fa9b10..7bb93d80c53d0 100644 --- a/build-system/externs/amp.extern.js +++ b/build-system/externs/amp.extern.js @@ -56,7 +56,7 @@ var FormDataWrapperInterface = function() {}; FormDataWrapperInterface.prototype.entries = function() {}; FormDataWrapperInterface.prototype.getFormData = function() {}; -FormData.prototype.entries = function () {}; +FormData.prototype.entries = function() {}; /** * A type for Objects that can be JSON serialized or that come from @@ -111,7 +111,6 @@ ExtensionPayload.prototype.v; /** @type {!Array|string|undefined} */ ExtensionPayload.prototype.i; - /** * @typedef {?JsonObject|undefined|string|number|!Array} */ @@ -121,7 +120,7 @@ var JsonValue; * @constructor * @dict */ -function VideoAnalyticsDetailsDef() {}; +function VideoAnalyticsDetailsDef() {} /** @type {boolean} */ VideoAnalyticsDetailsDef.prototype.autoplay; /** @type {number} */ @@ -143,7 +142,6 @@ VideoAnalyticsDetailsDef.prototype.state; /** @type {number} */ VideoAnalyticsDetailsDef.prototype.width; - // Node.js global var process = {}; process.env; @@ -164,7 +162,7 @@ window.context.experimentToggles; window.context.master; window.context.isMaster; window.context.ampcontextVersion; -window.context.ampcontextFilepath +window.context.ampcontextFilepath; window.context.canary; window.context.canonicalUrl; window.context.consentSharedData; @@ -256,6 +254,8 @@ AmpConfigType.prototype.runtime; AmpConfigType.prototype.test; /* @public {string|undefined} */ AmpConfigType.prototype.spt; +/* @public {boolean|undefined} */ +AmpConfigType.prototype.esm; /** @type {!AmpConfigType} */ window.AMP_CONFIG; @@ -354,15 +354,15 @@ ReactDatesConstants.HORIZONTAL_ORIENTATION; var Inputmask = class {}; /** @param {!Object} unusedOpts */ -Inputmask.extendAliases = function (unusedOpts) {}; +Inputmask.extendAliases = function(unusedOpts) {}; /** @param {!Object} unusedOpts */ -Inputmask.extendDefaults = function (unusedOpts) {}; +Inputmask.extendDefaults = function(unusedOpts) {}; /** @param {!Element} unusedElement */ -Inputmask.prototype.mask = function (unusedElement) {}; +Inputmask.prototype.mask = function(unusedElement) {}; -Inputmask.prototype.remove = function () {}; +Inputmask.prototype.remove = function() {}; /** @dict */ window.AMP.dependencies = {}; @@ -380,7 +380,7 @@ IntersectionObserverEntry.prototype.rootBounds; // TODO (remove after we update closure compiler externs) window.PerformancePaintTiming; window.PerformanceObserver; -Object.prototype.entryTypes +Object.prototype.entryTypes; /** @typedef {number} */ var time; @@ -391,7 +391,6 @@ var time; */ var UnlistenDef; - /** * Just an element, but used with AMP custom elements.. * @typedef {!Element} @@ -410,27 +409,27 @@ AmpElement.prototype.elementName = function() {}; var Signals = class {}; /** - * @param {string} unusedName - * @return {number|!Error|null} - */ + * @param {string} unusedName + * @return {number|!Error|null} + */ Signals.prototype.get = function(unusedName) {}; /** - * @param {string} unusedName - * @return {!Promise