@atomist/automation-client
Version:
Atomist API for software low-level client
162 lines • 7.26 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const enrichment_1 = require("@atomist/tree-path/manipulation/enrichment");
const expressionEngine_1 = require("@atomist/tree-path/path/expressionEngine");
const pathExpression_1 = require("@atomist/tree-path/path/pathExpression");
const utils_1 = require("@atomist/tree-path/path/utils");
const _ = require("lodash");
const logger_1 = require("../../internal/util/logger");
const projectUtils_1 = require("../../project/util/projectUtils");
const sourceLocationUtils_1 = require("../../project/util/sourceLocationUtils");
const FileHits_1 = require("./FileHits");
const FileParser_1 = require("./FileParser");
/**
* Integrate path expressions with project operations to find all matches
* @param p project
* @param globPatterns file glob patterns
* @param parserOrRegistry parser for files
* @param pathExpression path expression string or parsed
* @param functionRegistry registry to look for path expression functions in
* @return {Promise<MatchResult[]>} hit records for each matching file
*/
function findMatches(p, parserOrRegistry, globPatterns, pathExpression, functionRegistry) {
return findFileMatches(p, parserOrRegistry, globPatterns, pathExpression, functionRegistry)
.then(fileHits => _.flatten(fileHits.map(f => f.matches)));
}
exports.findMatches = findMatches;
function findFileMatches(p, parserOrRegistry, globPatterns, pathExpression, functionRegistry) {
return __awaiter(this, void 0, void 0, function* () {
const parsed = utils_1.toPathExpression(pathExpression);
const parser = findParser(parsed, parserOrRegistry);
if (!parser) {
throw new Error(`Cannot find parser for path expression [${pathExpression}]: Using ${parserOrRegistry}`);
}
const files = yield projectUtils_1.saveFromFiles(p, globPatterns, file => parseFile(parser, parsed, functionRegistry, p, file));
const all = yield Promise.all(files);
return all.filter(x => !!x);
});
}
exports.findFileMatches = findFileMatches;
function parseFile(parser, pex, functionRegistry, p, file) {
return __awaiter(this, void 0, void 0, function* () {
return parser.toAst(file)
.then(topLevelProduction => {
logger_1.logger.debug("Successfully parsed file '%s' to AST with root node named '%s'. Will execute '%s'", file.path, topLevelProduction.$name, pathExpression_1.stringify(pex));
enrichment_1.defineDynamicProperties(topLevelProduction);
const fileNode = {
path: file.path,
name: file.name,
$name: file.name,
$children: [topLevelProduction],
};
const r = expressionEngine_1.evaluateExpression(fileNode, pex, functionRegistry);
if (pathExpression_1.isSuccessResult(r)) {
logger_1.logger.debug("%d matches in file '%s'", r.length, file.path);
return fillInSourceLocations(file, r)
.then(locatedNodes => new FileHits_1.FileHit(p, file, fileNode, locatedNodes));
}
else {
logger_1.logger.debug("No matches in file '%s'", file.path);
return undefined;
}
})
.catch(err => {
logger_1.logger.info("Failed to parse file '%s': %s", file.path, err);
return undefined;
});
});
}
/**
* Use file content to fill in LocatedTreeNode.sourceLocation
* @param {File} f
* @param {TreeNode[]} nodes
* @return {Promise<LocatedTreeNode[]>}
*/
function fillInSourceLocations(f, nodes) {
if (nodes.length === 0) {
// Optimization.
// In this case, let's not read the file content and leave source locations undefined
return Promise.resolve(nodes);
}
return f.getContent()
.then(content => {
nodes.forEach(n => {
n.sourceLocation = sourceLocationUtils_1.toSourceLocation(f, content, n.$offset);
});
return nodes;
});
}
/**
* Convenient method to find all values of matching nodes--
* typically, terminals such as identifiers
* @param p project
* @param globPatterns file glob pattern
* @param parserOrRegistry parser for files
* @param pathExpression path expression string or parsed
* @param functionRegistry registry to look for path expression functions in
* @return {Promise<TreeNode[]>} hit record for each matching file
*/
function findValues(p, parserOrRegistry, globPatterns, pathExpression, functionRegistry) {
return findFileMatches(p, parserOrRegistry, globPatterns, pathExpression, functionRegistry)
.then(fileHits => _.flatten(fileHits.map(f => f.matches))
.map(m => m.$value));
}
exports.findValues = findValues;
/**
* Integrate path expressions with project operations to find all matches
* of a path expression and zap them. Use with care!
* @param p project
* @param globPatterns file glob pattern
* @param parserOrRegistry parser for files
* @param pathExpression path expression string or parsed
* @param opts options for handling whitespace
* @return {Promise<TreeNode[]>} hit record for each matching file
*/
function zapAllMatches(p, parserOrRegistry, globPatterns, pathExpression, opts = {}) {
return doWithAllMatches(p, parserOrRegistry, globPatterns, pathExpression, m => m.zap(opts));
}
exports.zapAllMatches = zapAllMatches;
/**
* Integrate path expressions with project operations to find all matches
* of a path expression and perform a mutation on them them. Use with care!
* @param p project
* @param globPatterns file glob pattern
* @param parserOrRegistry parser for files
* @param pathExpression path expression string or parsed
* @param todo what to do with matches
* @return {Promise<TreeNode[]>} hit record for each matching file
*/
function doWithAllMatches(p, parserOrRegistry, globPatterns, pathExpression, todo) {
return findFileMatches(p, parserOrRegistry, globPatterns, pathExpression)
.then(fileHits => {
fileHits.forEach(fh => {
const sorted = fh.matches.sort((m1, m2) => m1.$offset - m2.$offset);
sorted.forEach(m => {
todo(m);
});
});
return p.flush();
});
}
exports.doWithAllMatches = doWithAllMatches;
function findParser(pathExpression, fp) {
if (FileParser_1.isFileParser(fp)) {
if (!!fp.validate) {
fp.validate(pathExpression);
}
return fp;
}
else {
return fp.parserFor(pathExpression);
}
}
exports.findParser = findParser;
//# sourceMappingURL=astUtils.js.map