Skip to content

Commit

Permalink
Add url REPLACE macro (ampproject#13130)
Browse files Browse the repository at this point in the history
* add-replace-filter

* Refactor space handling

* Toggle off next arg

* Do what test describes
  • Loading branch information
calebcordry authored and RanAbram committed Mar 12, 2018
1 parent 35eca4d commit 4b0e8a5
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 6 deletions.
28 changes: 28 additions & 0 deletions extensions/amp-analytics/0.1/test/test-variables.js
Expand Up @@ -193,6 +193,34 @@ describe('amp-analytics.VariableService', function() {
'S7Uc5ZmODduHWdplzrZ7Jsnqx')
);
});

it('replaces common use case', () => {
return check('REPLACE(this-is-a-test, `-`)', 'thisisatest');
});

it('replaces three args', () => {
return check('REPLACE(this-is-a-test, `-`, *)', 'this*is*a*test');
});

it('replaces backticks optional', () => {
return check('REPLACE(this-is-a-test, -, **)', 'this**is**a**test');
});

it('replaces not trimming spaces in backticks', () => {
return check('REPLACE(this-is-a-test, ` -`)', 'this-is-a-test');
});

it('replaces respecting space as arg', () => {
return check('REPLACE(this-is-a-test, `-`, ` `)', 'this%20is%20a%20test');
});

it('replaces respecting backticks', () => {
return check('REPLACE(`this-,is-,a-,test`, `-,`)', 'thisisatest');
});

it('replace with no third arg', () => {
return check('REPLACE(thi@s-is-a-te@st, `-|@`)', 'thisisatest');
});
});

describe('getNameArgs:', () => {
Expand Down
18 changes: 18 additions & 0 deletions extensions/amp-analytics/0.1/variables.js
Expand Up @@ -98,6 +98,23 @@ function defaultMacro(value, defaultValue) {
return value;
}

/**
* @param {string} string input to be replaced
* @param {string} matchPattern string representation of regex pattern
* @param {string=} opt_newSubStr pattern to be substituted in
* @returns {string}
*/
function replaceMacro(string, matchPattern, opt_newSubStr) {
if (!matchPattern) {
user().warn(TAG, 'REPLACE macro must have two or more arguments');
}
if (!opt_newSubStr) {
opt_newSubStr = '';
}
const regex = new RegExp(matchPattern, 'g');
return string.replace(regex, opt_newSubStr);
}


/**
* Provides support for processing of advanced variable syntax like nested
Expand Down Expand Up @@ -126,6 +143,7 @@ export class VariableService {
this.register_('HASH', this.hashMacro_.bind(this));
this.register_('IF',
(value, thenValue, elseValue) => value ? thenValue : elseValue);
this.register_('REPLACE', replaceMacro);
}

/**
Expand Down
30 changes: 24 additions & 6 deletions src/service/url-expander/expander.js
Expand Up @@ -16,6 +16,8 @@

import {rethrowAsync} from '../../log';

export const PARSER_IGNORE_FLAG = '`';

/** Rudamentary parser to handle nested Url replacement. */
export class Expander {

Expand Down Expand Up @@ -86,13 +88,14 @@ export class Expander {
let matchIndex = 0;
let match = matches[matchIndex];
let numOfPendingCalls = 0;
let ignoringChars = false;
let nextArgShouldBeRaw = false;

const evaluateNextLevel = () => {
let builder = '';
const results = [];

while (urlIndex < url.length && matchIndex <= matches.length) {

if (match && urlIndex === match.start) {
let binding;
// find out where this keyword is coming from
Expand Down Expand Up @@ -127,25 +130,40 @@ export class Expander {
builder = '';
}

else if (numOfPendingCalls && url[urlIndex] === ',') {
else if (url[urlIndex] === PARSER_IGNORE_FLAG) {
if (!ignoringChars) {
ignoringChars = true;
nextArgShouldBeRaw = true;
builder = '';
} else {
ignoringChars = false;
}
urlIndex++;
}

else if (numOfPendingCalls && url[urlIndex] === ',' && !ignoringChars) {
if (builder.length) {
results.push(builder.trim());
const nextArg = nextArgShouldBeRaw ? builder : builder.trim();
results.push(nextArg);
nextArgShouldBeRaw = false;
}
// support existing two comma format
// eg CLIENT_ID(__ga,,ga-url)
if (url[urlIndex + 1] === ',') {
results.push('');
results.push(''); // TODO(ccordry): may want this to be undefined at some point
urlIndex++;
}
builder = '';
urlIndex++;
}

else if (url[urlIndex] === ')') {
else if (url[urlIndex] === ')' && !ignoringChars) {
urlIndex++;
numOfPendingCalls--;
const binding = stack.pop();
results.push(builder.trim());
const nextArg = nextArgShouldBeRaw ? builder : builder.trim();
results.push(nextArg);
nextArgShouldBeRaw = false;
const value = this.evaluateBinding_(binding, results);
return value;
}
Expand Down
18 changes: 18 additions & 0 deletions test/functional/url-expander/test-expander.js
Expand Up @@ -174,6 +174,24 @@ describes.realWin('Expander', {
return expect(expander.expand('TRIM(FAKE(aaaaa))', mockBindings))
.to.eventually.equal('');
});

it('ignores commas within backticks', () => {
const url = 'CONCAT(`he,llo`,UPPERCASE(world)';
return expect(expander.expand(url, mockBindings))
.to.eventually.equal('he,lloWORLD');
});

it('ignores left parentheses within backticks', () => {
const url = 'CONCAT(hello, `wo((rld`)';
return expect(expander.expand(url, mockBindings))
.to.eventually.equal('hellowo((rld');
});

it('ignores right parentheses within backticks', () => {
const url = 'CONCAT(`hello)`,UPPERCASE(world)';
return expect(expander.expand(url, mockBindings))
.to.eventually.equal('hello)WORLD');
});
});
});

0 comments on commit 4b0e8a5

Please sign in to comment.