Resolve macros in VariableService.#22379
Resolve macros in VariableService.#22379calebcordry wants to merge 17 commits intoampproject:masterfrom calebcordry:var-encoding-bug
Conversation
|
Is this PR blocked by anything? Or is it ready for review? |
|
@lannka I keep forgetting about this PR, but it is ready for review. |
zhouyx
left a comment
There was a problem hiding this comment.
@calebcordry Can we sync on the fix offline sometime? I want to understand what approaches has been discussed before.
From what I found, you're trying to expand the macros in variables before replacing them. Which avoids the encoding issue. However I have two concerns. 1. expandTemplate and expandUrlAsync used to be two different expansion. With this change we start to mix them together. 2. Instead of trying to resolve macro at event trigger time, we may resolve macros too early. TIMESTAMP for example.
| this.linkerReader_ = linkerReaderServiceFor(this.ampdoc_.win); | ||
|
|
||
| /** @const @private {!../../../src/service/url-replacements-impl.UrlReplacements} */ | ||
| this.urlReplacementService_ = Services.urlReplacementsForDoc( |
There was a problem hiding this comment.
We can't do this. Instead we'll have to call Services.urlReplacementsForDoc(element) for every element we want to expand. Because FIE doesn't have its own ampdoc, but it has its own urlReplacementService.
There was a problem hiding this comment.
Moved to get urlReplacementService from the element inside the expandTemplate call.
|
Sounds good, let's plan on syncing sometime Thursday. |
|
sgtm |
| * @return {!Promise<string>} | ||
| */ | ||
| function serializeResourceTiming(ampdoc, resourceTimingSpec) { | ||
| function serializeResourceTiming(ampdoc, element, resourceTimingSpec) { |
There was a problem hiding this comment.
nit: can we get rid of ampdoc here?
There was a problem hiding this comment.
I think we need it to get the win? Let me know if I am missing something.
There was a problem hiding this comment.
Still not sure about this one.
There was a problem hiding this comment.
Oh I see, thanks, done.
| 'p:nth-child(2)', | ||
| ].map(selectorExpansionTest); | ||
|
|
||
| it('does not expands selector with platform variable', () => { |
There was a problem hiding this comment.
Any way to preserve the existing behavior?
There was a problem hiding this comment.
Is there a reason we don't want to use the platform macros here? We could add something like a noPlatform flag for certain callers if you like. This would come with the cost that these callers could not use nested.
There was a problem hiding this comment.
This behavior has changed, let me know if you think we need to support not expanding macros in certain cases.
There was a problem hiding this comment.
I guess it's fine. Please add a note to the code. Thanks
There was a problem hiding this comment.
Added a note to expandTemplate
|
Is this PR still active? |
|
Yep working on it now. |
|
@zhouyx I think this is finally ready for another round of review |
| * @return {!Promise<string>} | ||
| */ | ||
| function serializeResourceTiming(ampdoc, resourceTimingSpec) { | ||
| function serializeResourceTiming(ampdoc, element, resourceTimingSpec) { |
| }); | ||
| }) | ||
| .then(() => | ||
| // TODO: fix this, should be 'AAA(BBB(1,2))' |
There was a problem hiding this comment.
nit: remove since we are not going to fix it.
| // valid macros when they are seen in `Variables#expandTemplate`. | ||
| check('${foo}', 'AAA(BBB(1%2C2))', { | ||
| 'foo': 'AAA(BBB(1,2))', | ||
| }) |
| }) | ||
| ) | ||
| .then(() => | ||
| // TODO: fix this, should be 'AAA(1,2)%26BBB(3,4)%26CCC(5,6)%26DDD(7,8) |
| expandTemplateSync(template, options) { | ||
| return template.replace(/\${([^}]*)}/g, (match, key) => { | ||
| expandTemplate(template, options, element) { | ||
| return this.asyncStringReplace_(template, /\${([^}]*)}/g, (match, key) => { |
There was a problem hiding this comment.
You may have explained this before. I'm not an expert on regex.
${abc${def}} would break right? If so can we add a test to cover that. Thanks
There was a problem hiding this comment.
That is correct. Added test.
| * @param {Function} replacer | ||
| * @return {!Promise<string>} | ||
| */ | ||
| asyncStringReplace_(str, regex, replacer) { |
There was a problem hiding this comment.
If I understand the code correctly. What we want here to an array of promise that waits for each variable to resolve. Personally I think this helper method makes the code more difficult to understand.
Can we inline the code as previous and do
const promises = []
str.replace(regex, () => {
// some operation
promises.push(promise)
})
return Promise.all(promises)
So that we can get rid of the stringBuilder here. Thanks
There was a problem hiding this comment.
Talked offline. Moved asyncStringReplace to a separate function in string.js
| 'p:nth-child(2)', | ||
| ].map(selectorExpansionTest); | ||
|
|
||
| it('does not expands selector with platform variable', () => { |
There was a problem hiding this comment.
I guess it's fine. Please add a note to the code. Thanks
|
|
||
| it('expands nested vars (encode once)', () => { | ||
| check('${a}', 'https%3A%2F%2Fwww.google.com%2Fa%3Fb%3D1%26c%3D2', vars); | ||
| return check( |
There was a problem hiding this comment.
Are there test coverage for expanding the nested macro? Please help link to the test. Thanks.
Also given there are a bunch of special cases, it would be great to add a manual test file which helps demonstrate all the expected behaviors. Thanks
There was a problem hiding this comment.
Added a manual file, let me know if there is anything else that you can think of. There is a test here
amphtml/extensions/amp-analytics/0.1/test/test-variables.js
Lines 148 to 153 in d165120
that shows the new behavior, let me know if have idea for more.
|
@zhouyx this should be ready for another round of review whenever you have time. Thanks! |
| expandTemplateWithUrlParams_(spec, expansionOptions) { | ||
| return this.variableService_ | ||
| .expandTemplate(spec, expansionOptions) | ||
| .expandTemplate(spec, expansionOptions, this.element) |
There was a problem hiding this comment.
Since we pass the binding info to expandUrlAsync, do we want to pass the same to expandTemplate?
There was a problem hiding this comment.
I think this only matters for RESOURCE_TIMING as the way expandTemplate is now written it will try to get the bindings from the element if not passed in. If you prefer to explicitly pass it the bindings everywhere, I am happy to do so.
| const bindings = this.variableService_.getMacros(this.element_); | ||
| return this.variableService_ | ||
| .expandTemplate(template, expansionOptions) | ||
| .expandTemplate(template, expansionOptions, this.element_) |
| this.requestOriginPromise_ = this.variableService_ | ||
| // expand variables in request origin | ||
| .expandTemplate(this.requestOrigin_, requestOriginExpansionOpt) | ||
| .expandTemplate( |
There was a problem hiding this comment.
This one should definitely have the bindings, as it will include the RESOURCE_TIMING macro. Done.
|
|
||
| const basePromise = variableService | ||
| .expandTemplate(msg, expansionOption) | ||
| .expandTemplate(msg, expansionOption, element) |
|
|
||
| it('expands nested vars (encode once)', () => { | ||
| check('${a}', 'https%3A%2F%2Fwww.google.com%2Fa%3Fb%3D1%26c%3D2', vars); | ||
| return check( |
| * @param {Function} replacer | ||
| * @return {!Promise<string>} | ||
| */ | ||
| export function asyncStringReplace(str, regex, replacer) { |
There was a problem hiding this comment.
Please add unit test for this function
There was a problem hiding this comment.
Actually hit a bug here with variable number of capture groups. Didn't think of this when we moved to make it generic. Working on fix.
There was a problem hiding this comment.
OK fixed :) should work with any number of capture groups.
| You can use the ${} format in conjuction with nested macros, as long as there are no nested ${}. | ||
| See combo below. | ||
| --> | ||
| <amp-analytics> |
There was a problem hiding this comment.
Thanks for the manual test file
There was a problem hiding this comment.
It was a good idea 🙂. You are welcome.
|
@zhouyx I think this is ready for another round whenever you have time. Thanks! |
|
is this still needed? or did @micajuine-ho take over? |
|
saw #26271 |
Closes #21751
Changes
VariableService.expandTemplateto resolve macros through theUrlReplacementServiceas it encounters them. This avoids the problem of thevariableServiceencoding certain macros before they are resolved.$,(and,would be encoded in nested macros etc.One note: I had to pass the element along everywhere this is called to check if
amp-analyticsis sandboxed. I am open to other suggestions on how this could be accomplished.