2017-07-31 08:14:19 +00:00
|
|
|
/**
|
|
|
|
* Copyright 2017 Google Inc. 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 Message = require('../Message');
|
|
|
|
|
|
|
|
const PUPPETEER_VERSION = require('../../../package.json').version;
|
|
|
|
|
|
|
|
module.exports = function(sources) {
|
|
|
|
let messages = [];
|
|
|
|
let commands = [];
|
|
|
|
for (let source of sources) {
|
|
|
|
const text = source.text();
|
|
|
|
const commandStartRegex = /<!--\s*gen:([a-z]+)(?:\s*\(\s*([^)]*)\s*\))?\s*-->/ig;
|
|
|
|
const commandEndRegex = /<!--\s*gen:stop\s*-->/ig;
|
|
|
|
let start;
|
|
|
|
|
|
|
|
while (start = commandStartRegex.exec(text)) { // eslint-disable-line no-cond-assign
|
|
|
|
commandEndRegex.lastIndex = commandStartRegex.lastIndex;
|
|
|
|
const end = commandEndRegex.exec(text);
|
|
|
|
if (!end) {
|
|
|
|
messages.push(Message.error(`Failed to find 'gen:stop' for comamnd ${start[0]}`));
|
|
|
|
break;
|
|
|
|
}
|
2017-07-31 10:23:29 +00:00
|
|
|
const name = start[1];
|
|
|
|
const arg = start[2];
|
|
|
|
const from = commandStartRegex.lastIndex;
|
|
|
|
const to = end.index;
|
2017-07-31 08:14:19 +00:00
|
|
|
commandStartRegex.lastIndex = commandEndRegex.lastIndex;
|
2017-07-31 10:23:29 +00:00
|
|
|
commands.push({name, arg, from, to, source});
|
2017-07-31 08:14:19 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-31 10:23:29 +00:00
|
|
|
|
|
|
|
commands = validateCommands(commands, messages);
|
|
|
|
|
|
|
|
// Extract copied text.
|
|
|
|
let copyIds = new Map();
|
|
|
|
for (let command of commands) {
|
|
|
|
if (command.name !== 'copy')
|
|
|
|
continue;
|
|
|
|
const copyText = command.source.text().substring(command.from, command.to);
|
|
|
|
copyIds.set(command.arg, copyText);
|
|
|
|
}
|
|
|
|
|
2017-07-31 08:14:19 +00:00
|
|
|
let changedSources = new Set();
|
2017-07-31 10:23:29 +00:00
|
|
|
// Iterate commands in reverse order so that edits don't conflict.
|
|
|
|
commands.sort((a, b) => b.from - a.from);
|
2017-07-31 08:14:19 +00:00
|
|
|
for (let command of commands) {
|
|
|
|
let newText = command.source.text();
|
2017-07-31 10:23:29 +00:00
|
|
|
if (command.name === 'version') {
|
2017-07-31 08:14:19 +00:00
|
|
|
newText = replaceInText(newText, command.from, command.to, PUPPETEER_VERSION);
|
2017-07-31 10:23:29 +00:00
|
|
|
} else if (command.name === 'paste') {
|
|
|
|
let copyText = copyIds.get(command.arg);
|
|
|
|
copyText = `\n<!-- Text below is automatically copied from "gen:copy(${command.arg})" -->` + copyText;
|
|
|
|
newText = replaceInText(newText, command.from, command.to, copyText);
|
|
|
|
}
|
2017-07-31 08:14:19 +00:00
|
|
|
if (command.source.setText(newText))
|
|
|
|
changedSources.add(command.source);
|
|
|
|
}
|
|
|
|
for (source of changedSources)
|
|
|
|
messages.push(Message.warning(`GEN: updated ${source.projectPath()}`));
|
|
|
|
return messages;
|
|
|
|
};
|
|
|
|
|
2017-07-31 10:23:29 +00:00
|
|
|
/**
|
|
|
|
* @param {!Array<!Object>} commands
|
|
|
|
* @param {!Array<!Message>} outMessages
|
|
|
|
* @return {!Array<!Object>}
|
|
|
|
*/
|
|
|
|
function validateCommands(commands, outMessages) {
|
|
|
|
// Filter sane commands
|
|
|
|
let goodCommands = commands.filter(command => {
|
|
|
|
if (command.name === 'version')
|
|
|
|
return check(command, !command.arg, `"gen:version" should not have argument`);
|
|
|
|
if (command.name === 'copy')
|
|
|
|
return check(command, command.arg, `"gen:copy" should have argument - copyId`);
|
|
|
|
if (command.name === 'paste')
|
|
|
|
return check(command, command.arg, `"gen:paste" should have argument - name of the register to paste from`);
|
|
|
|
check(command, false, `Unknown command: "gen:${command.name}"`);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Make sure copy commands don't clash ids.
|
|
|
|
let copyIds = new Map();
|
|
|
|
goodCommands = goodCommands.filter(command => {
|
|
|
|
if (command.name !== 'copy')
|
|
|
|
return true;
|
|
|
|
const duplicateCopy = copyIds.get(command.arg);
|
|
|
|
const duplicatePath = duplicateCopy ? duplicateCopy.source.projectPath() : '';
|
|
|
|
if (check(command, !duplicateCopy, `"gen:copy" tries to re-define copy id "${command.arg}" - previously defined in ${duplicatePath}`)) {
|
|
|
|
copyIds.set(command.arg, command);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Make sure paste commands refer to proper ids, and every copyId is used at least
|
|
|
|
// once.
|
|
|
|
let unusedCopyIds = new Set(copyIds.keys());
|
|
|
|
goodCommands = goodCommands.filter(command => {
|
|
|
|
if (command.name !== 'paste')
|
|
|
|
return true;
|
|
|
|
unusedCopyIds.delete(command.arg);
|
|
|
|
if (check(command, copyIds.has(command.arg), `"gen:paste" refers to unknown copy id "${command.arg}"`))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
for (let copyId of unusedCopyIds) {
|
|
|
|
let command = copyIds.get(copyId);
|
|
|
|
check(command, false, `"gen:copy" defines unused copy id "${copyId}"`);
|
|
|
|
}
|
|
|
|
return goodCommands;
|
|
|
|
|
|
|
|
function check(command, condition, message) {
|
|
|
|
if (condition)
|
|
|
|
return true;
|
|
|
|
outMessages.push(Message.error(`${command.source.projectPath()}: ${message}`));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-31 08:14:19 +00:00
|
|
|
function replaceInText(text, from, to, newText) {
|
|
|
|
return text.substring(0, from) + newText + text.substring(to);
|
|
|
|
}
|