UNPKG

9.07 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
5 * This code may only be used under the BSD style license found at
6 * http://polymer.github.io/LICENSE.txt
7 * The complete set of authors may be found at
8 * http://polymer.github.io/AUTHORS.txt
9 * The complete set of contributors may be found at
10 * http://polymer.github.io/CONTRIBUTORS.txt
11 * Code distributed by Google as part of the polymer project is also
12 * subject to an additional IP rights grant found at
13 * http://polymer.github.io/PATENTS.txt
14 */
15var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
16 return new (P || (P = Promise))(function (resolve, reject) {
17 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
20 step((generator = generator.apply(thisArg, _arguments || [])).next());
21 });
22};
23Object.defineProperty(exports, "__esModule", { value: true });
24/// <reference path="../../custom_typings/main.d.ts" />
25const path = require("path");
26const model_1 = require("../model/model");
27const analysis_context_1 = require("./analysis-context");
28const cancel_token_1 = require("./cancel-token");
29class NoKnownParserError extends Error {
30}
31exports.NoKnownParserError = NoKnownParserError;
32/**
33 * A static analyzer for web projects.
34 *
35 * An Analyzer can load and parse documents of various types, and extract
36 * arbitrary information from the documents, and transitively load
37 * dependencies. An Analyzer instance is configured with parsers, and scanners
38 * which do the actual work of understanding different file types.
39 */
40class Analyzer {
41 constructor(options) {
42 if (options.__contextPromise) {
43 this._urlLoader = options.urlLoader;
44 this.urlResolver = options.urlResolver;
45 this._analysisComplete = options.__contextPromise;
46 }
47 else {
48 const context = new analysis_context_1.AnalysisContext(options);
49 this.urlResolver = context.resolver;
50 this._urlLoader = context.loader;
51 this._analysisComplete = Promise.resolve(context);
52 }
53 }
54 /**
55 * Loads, parses and analyzes the root document of a dependency graph and its
56 * transitive dependencies.
57 */
58 analyze(urls, options = {}) {
59 return __awaiter(this, void 0, void 0, function* () {
60 const previousAnalysisComplete = this._analysisComplete;
61 const uiUrls = this.brandUserInputUrls(urls);
62 let filesWithParsers;
63 this._analysisComplete = (() => __awaiter(this, void 0, void 0, function* () {
64 const previousContext = yield previousAnalysisComplete;
65 filesWithParsers =
66 this._filterFilesByParsableExtension(uiUrls, previousContext);
67 return yield previousContext.analyze(filesWithParsers, options.cancelToken || cancel_token_1.neverCancels);
68 }))();
69 const context = yield this._analysisComplete;
70 const resolvedUrls = context.resolveUserInputUrls(filesWithParsers);
71 return this._constructAnalysis(context, resolvedUrls);
72 });
73 }
74 analyzePackage(options = {}) {
75 return __awaiter(this, void 0, void 0, function* () {
76 const previousAnalysisComplete = this._analysisComplete;
77 let analysis;
78 this._analysisComplete = (() => __awaiter(this, void 0, void 0, function* () {
79 const previousContext = yield previousAnalysisComplete;
80 if (!previousContext.loader.readDirectory) {
81 throw new Error(`This analyzer doesn't support analyzerPackage, ` +
82 `the urlLoader can't list the files in a directory.`);
83 }
84 const allFiles = yield previousContext.loader.readDirectory('', true);
85 // TODO(rictic): parameterize this, perhaps with polymer.json.
86 const filesInPackage = allFiles.filter((file) => !model_1.Analysis.isExternal(file));
87 const filesWithParsers = this._filterFilesByParsableExtension(filesInPackage, previousContext);
88 const newContext = yield previousContext.analyze(filesWithParsers, options.cancelToken || cancel_token_1.neverCancels);
89 const resolvedFilesWithParsers = newContext.resolveUserInputUrls(filesWithParsers);
90 analysis = this._constructAnalysis(newContext, resolvedFilesWithParsers);
91 return newContext;
92 }))();
93 yield this._analysisComplete;
94 return analysis;
95 });
96 }
97 _filterFilesByParsableExtension(filenames, context) {
98 const extensions = new Set(context.parsers.keys());
99 return filenames.filter((fn) => extensions.has(path.extname(fn).substring(1)));
100 }
101 _constructAnalysis(context, urls) {
102 const getUrlResultPair = (url) => [url, context.getDocument(url)];
103 return new model_1.Analysis(new Map(urls.map(getUrlResultPair)), context);
104 }
105 /**
106 * Clears all information about the given files from our caches, such that
107 * future calls to analyze() will reload these files if they're needed.
108 *
109 * The analyzer assumes that if this method isn't called with a file's url,
110 * then that file has not changed and does not need to be reloaded.
111 *
112 * @param urls The urls of files which may have changed.
113 */
114 filesChanged(urls) {
115 return __awaiter(this, void 0, void 0, function* () {
116 const previousAnalysisComplete = this._analysisComplete;
117 this._analysisComplete = (() => __awaiter(this, void 0, void 0, function* () {
118 const previousContext = yield previousAnalysisComplete;
119 return yield previousContext.filesChanged(this.brandUserInputUrls(urls));
120 }))();
121 yield this._analysisComplete;
122 });
123 }
124 /**
125 * Clear all cached information from this analyzer instance.
126 *
127 * Note: if at all possible, instead tell the analyzer about the specific
128 * files that changed rather than clearing caches like this. Caching provides
129 * large performance gains.
130 */
131 clearCaches() {
132 return __awaiter(this, void 0, void 0, function* () {
133 const previousAnalysisComplete = this._analysisComplete;
134 this._analysisComplete = (() => __awaiter(this, void 0, void 0, function* () {
135 const previousContext = yield previousAnalysisComplete;
136 return yield previousContext.clearCaches();
137 }))();
138 yield this._analysisComplete;
139 });
140 }
141 /**
142 * Returns a copy of the analyzer. If options are given, the AnalysisContext
143 * is also forked and individual properties are overridden by the options.
144 * is forked with the given options.
145 *
146 * When the analysis context is forked, its cache is preserved, so you will
147 * see a mixture of pre-fork and post-fork contents when you analyze with a
148 * forked analyzer.
149 *
150 * Note: this feature is experimental. It may be removed without being
151 * considered a breaking change, so check for its existence before calling
152 * it.
153 */
154 _fork(options) {
155 const contextPromise = (() => __awaiter(this, void 0, void 0, function* () {
156 return options ?
157 (yield this._analysisComplete)._fork(undefined, options) :
158 (yield this._analysisComplete);
159 }))();
160 return new Analyzer({
161 urlLoader: this._urlLoader,
162 urlResolver: this.urlResolver,
163 __contextPromise: contextPromise
164 });
165 }
166 /**
167 * Returns `true` if the provided resolved URL can be loaded. Obeys the
168 * semantics defined by `UrlLoader` and should only be used to check
169 * resolved URLs.
170 */
171 canLoad(resolvedUrl) {
172 return this._urlLoader.canLoad(resolvedUrl);
173 }
174 /**
175 * Loads the content at the provided resolved URL. Obeys the semantics
176 * defined by `UrlLoader` and should only be used to attempt to load resolved
177 * URLs.
178 */
179 load(resolvedUrl) {
180 return __awaiter(this, void 0, void 0, function* () {
181 const result = yield (yield this._analysisComplete).load(resolvedUrl);
182 if (!result.successful) {
183 throw new Error(result.error);
184 }
185 return result.value;
186 });
187 }
188 /**
189 * Resoves `url` to a new location.
190 */
191 resolveUrl(url) {
192 return this.urlResolver.resolve(url);
193 }
194 // Urls from the user are assumed to be package relative
195 brandUserInputUrls(urls) {
196 return urls;
197 }
198}
199exports.Analyzer = Analyzer;
200//# sourceMappingURL=analyzer.js.map
\No newline at end of file