UNPKG

9.54 kBMarkdownView Raw
1# mako-tree
2
3> The build tree structure used internally by [mako](https://github.com/makojs/core)
4
5[![npm version](https://img.shields.io/npm/v/mako-tree.svg)](https://www.npmjs.com/package/mako-tree)
6[![npm dependencies](https://img.shields.io/david/makojs/tree.svg)](https://david-dm.org/makojs/tree)
7[![npm dev dependencies](https://img.shields.io/david/dev/makojs/tree.svg)](https://david-dm.org/makojs/tree#info=devDependencies)
8[![build status](https://img.shields.io/travis/makojs/tree.svg)](https://travis-ci.org/makojs/tree)
9
10## Overview
11
12When working with mako build hooks, the first 2 arguments will be the current `file` and the build
13`tree` respectively. Currently, both of those APIs are contained in this module, as they tightly
14coupled and don't make much sense on their own. (at least at the current time)
15
16Throughout the "analyze" phase, a tree is being built up, starting from the list of entry files.
17Each file being processed adds any direct dependencies, which will then recursively be processed
18to find more dependencies. Each vertex in the graph corresponds to some sort of input file.
19
20During the "build" phase, the tree _may_ be trimmed down, such as the case where the entire
21dependency chain for a JS file will be combined into a single output file. By the end of the build,
22each vertex in the graph corresponds to an output file.
23
24## API
25
26> As mako continues to be developed and evolve, some documentation and guides dedicated to plugin
27authors will surface. For now, the following is purely the API available to both the `file` and
28`tree` parameters in plugins/hooks.
29
30The `Tree` constructor (documented below) is the primary export for the module. It must be used
31with the `new` keyword.
32
33```js
34var Tree = require('mako-tree');
35var tree = new Tree();
36```
37
38### Tree() *(constructor)*
39
40Each instance represents a build tree. Internally, a graph is used to manage the relationships
41between all the files being tracked.
42
43**NOTE:** All paths are assumed to be absolute, this library makes no attempt to set a base/root
44directory and maintain relative paths.
45
46### Tree#hasFile(location)
47
48Returns a `Boolean` reflecting if the file at the given `location` exists in this tree.
49
50### Tree#addFile(location)
51
52Adds a file at the given `location` to the tree, if it is not already present, and returns the
53corresponding `File` instance.
54
55### Tree#getFile(location)
56
57Returns the `File` instance for the file at the given `location`. It is assumed to already be part
58of the graph, and will throw an error if not found.
59
60### Tree#getFiles([options])
61
62Returns an `Array` of all the files in this graph.
63
64If `options.topological` is set, the returned list will be in
65[topological order](https://en.wikipedia.org/wiki/Topological_sorting), which respects all
66dependencies so processing is safe where order matters.
67
68If `options.objects` is set, the returned list will be `File` objects.
69
70### Tree#removeFile(location)
71
72Removes the file at the given `location` from the tree. To successfully remove a file, it must not
73be depended on by another file. This is mostly a plumbing function, and plugin authors are likely
74going to use `removeDependency()` instead.
75
76### Tree#isSource(location)
77
78Returns a `Boolean` telling whether or not the file at `location` is an entry file. (in other
79words, is not a dependency)
80
81### Tree#getEntries([options])
82
83Returns an `Array` of all the entry files in this graph. (in other words, files that are at the
84end of the dependency chains)
85
86If `options.from` is set, the returned list will only include entries that are reachable from that
87specified file.
88
89If `options.objects` is set, the returned list will be `File` objects.
90
91### Tree#hasDependency(parent, child)
92
93Returns a `Boolean` reflecting if the dependency relationship between `parent` and `child` already
94exists in the tree.
95
96### Tree#addDependency(parent, child)
97
98Adds a new dependency relationship to the graph setting `parent` as depending on `child`.
99
100If `child` is not already part of the tree, it will be added. However, if `parent` is not in the
101tree, that is assumed to be an error.
102
103This will return the `File` instance for the `child` file.
104
105### Tree#removeDependency(parent, child)
106
107Removes the specified dependency relationship, basically saying that `parent` no longer depends on
108`child`.
109
110### Tree#dependenciesOf(file, [options])
111
112Returns an `Array` of files that are dependencies of the given `file`.
113
114By default, it will only return the direct descendants, but setting `options.recursive` will return
115a flat list of all the files **down** the entire dependency chain.
116
117If `options.objects` is set, the returned list will be `File` objects.
118
119### Tree#hasDependant(child, parent)
120
121Returns a `Boolean` reflecting if the dependency relationship between `child` and `parent` already
122exists in the tree.
123
124### Tree#addDependant(child, parent)
125
126Adds a new dependency relationship to the graph setting `child` as depended on by `parent`.
127
128If `parent` is not already part of the tree, it will be added. However, if `child` is not in the
129tree, that is assumed to be an error.
130
131This will return the `File` instance for the `parent` file.
132
133### Tree#removeDependant(child, parent)
134
135Removes the specified dependency relationship, basically saying that `child` no longer is depended
136on by `parent`.
137
138### Tree#dependantsOf(file, [options])
139
140Returns an `Array` of files that depend on the given `file`.
141
142By default, it will only return the direct ancestors, but adding `options.recursive` will return a
143flat list of all the files **up** the entire dependency chain.
144
145If `options.objects` is set, the returned list will be `File` objects.
146
147### Tree#timing()
148
149Aggregates all the timers for all files in the tree. These stats are useful when trying to figure
150out which plugins/hooks are taking up the most time so they can hopefully be optimized.
151
152### Tree#size()
153
154Returns the number of files in the tree.
155
156### Tree#clone()
157
158Returns a new `Tree` object that is an effective clone of the original.
159
160### Tree#prune([entries])
161
162Removes any orphaned files from the graph. A file is considered orphaned if it has no path to any
163file marked as an entry.
164
165If `entries` is passed, (must be an `Array`) then any files that cannot reach _those_ files will
166be removed from the graph. (essentially overrides the internal list of entries)
167
168### File(location, tree, [entry]) *(constructor)*
169
170Each instance represents a file in the overall build. The `location` is an absolute path, `tree`
171is the tree that contains this particular file and `entry` flags a file as an entry.
172
173Entry files are uniquely handled, particularly when it comes to `Tree#prune()`. Any files that do
174not have a path to some entry file are considered orphaned, and will be pruned.
175
176### File#path
177
178The absolute path to where this file exists on disk.
179
180### File#type
181
182The current file type associated with this file. This value is used to determine what plugins/hooks
183need to be invoked at various stages.
184
185**NOTE:** plugins can modify this value if their work changes the file type. (such as compiling
186`coffee` into `js`)
187
188### File#contents
189
190This holds the current contents of the file. When first read, this property should be set, and
191subsequent changes to the source code should apply to this property.
192
193**NOTE:** must be set by a plugin.
194
195### File#output
196
197The absolute path to where this file should be written on disk.
198
199**NOTE:** must be set by a plugin.
200
201### File#analyzing
202
203An internal flag that helps mako know when a particular file is currently being analyzed. (to
204prevent race conditions and duplicating efforts) There is currently no public use for this
205property.
206
207### File#analyzed
208
209A flag that helps mako know when a particular file has already been analyzed, so it doesn't
210continuously analyze the same file during subsequent builds. Do not change this manually,
211instead use `File#dirty()`.
212
213### File#isEntry()
214
215Short-hand for `tree.isEntry(file.path)`.
216
217### File#hasDependency(child)
218
219Short-hand for `tree.hasDependency(file.path, child)`.
220
221### File#addDependency(child)
222
223Short-hand for `tree.addDependency(file.path, child)`.
224
225### File#removeDependency(child)
226
227Short-hand for `tree.removeDependency(file.path, child)`.
228
229### File#dependencies([options])
230
231Short-hand for `tree.dependenciesOf(file.path, options)`.
232
233### File#hasDependant(parent)
234
235Short-hand for `tree.hasDependant(file.path, parent)`.
236
237### File#addDependant(parent)
238
239Short-hand for `tree.addDependency(file.path, parent)`.
240
241### File#removeDependant(parent)
242
243Short-hand for `tree.removeDependant(file.path, parent)`.
244
245### File#dependants([options])
246
247Short-hand for `tree.dependantsOf(file.path, options)`.
248
249### File#dirty()
250
251Can be used by the `prewrite` hook to mark a file as "dirty" so that it should be analyzed again.
252
253For example, [mako-stat](http://github.com/makojs/stat) will use this method whenever the
254modification time for a file has changed, which indicates to mako that analyze needs to be run
255again for this file.
256
257### File#time(label)
258
259Start a timer using the given `label` to describe what is being timed. (eg: "read", "babel")
260For simple hooks/plugins, a single timer is all you need.
261
262If a plugin wants to have multiple timers, it should use it's name as a prefix. (eg: "js:pack",
263"css:dependencies")
264
265### File#timeEnd(label)
266
267Stops the timer using the given `label`.
268
269The value saved here will be aggregated by the tree to give a glimpse of the overall time spent
270by varying plugins.
271
272### File#clone(tree)
273
274Returns a new `File` object that is an effective clone of the original.