UNPKG

8.1 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`. If
99`child` is not already part of the tree, it will be added. (however, if `parent` is not in the tree,
100that is assumed to be an error) This will return the `File` instance for the `child` file.
101
102### Tree#removeDependency(parent, child)
103
104Removes the specified dependency relationship, basically saying that `parent` no longer depends on
105`child`)
106
107**NOTE:** If no other files depend on `child`, it will be removed from the tree. This allows
108plugins to only concern themselves with the relationships they are aware of, leaving the overall
109tree management to mako.
110
111### Tree#dependenciesOf(file, [options])
112
113Returns an `Array` of files that are dependencies of the given `file`.
114
115By default, it will only return the direct descendants, but setting `options.recursive` will return
116a flat list of all the files **down** the entire dependency chain.
117
118If `options.objects` is set, the returned list will be `File` objects.
119
120### Tree#dependantsOf(file, [options])
121
122Returns an `Array` of files that depend on the given `file`.
123
124By default, it will only return the direct ancestors, but adding `options.recursive` will return a
125flat list of all the files **up** the entire dependency chain.
126
127If `options.objects` is set, the returned list will be `File` objects.
128
129### Tree#clone()
130
131Returns a new `Tree` object that is an effective clone of the original.
132
133### Tree#prune([entries])
134
135Removes any orphaned files from the graph. A file is considered orphaned if it has no path to any
136file marked as an entry.
137
138If `entries` is passed, (must be an `Array`) then any files that cannot reach _those_ files will
139be removed from the graph. (essentially overrides the internal list of entries)
140
141### File(location, tree, [entry]) *(constructor)*
142
143Each instance represents a file in the overall build. The `location` is an absolute path, `tree`
144is the tree that contains this particular file and `entry` flags a file as an entry.
145
146Entry files are uniquely handled, particularly when it comes to `Tree#prune()`. Any files that do
147not have a path to some entry file are considered orphaned, and will be pruned.
148
149### File#path
150
151The absolute path to where this file exists on disk.
152
153### File#type
154
155The current file type associated with this file. This value is used to determine what plugins/hooks
156need to be invoked at various stages.
157
158**NOTE:** plugins can modify this value if their work changes the file type. (such as compiling
159`coffee` into `js`)
160
161### File#contents
162
163This holds the current contents of the file. When first read, this property should be set, and
164subsequent changes to the source code should apply to this property.
165
166**NOTE:** must be set by a plugin.
167
168### File#output
169
170The absolute path to where this file should be written on disk.
171
172**NOTE:** must be set by a plugin.
173
174### File#analyzing
175
176An internal flag that helps mako know when a particular file is currently being analyzed. (to
177prevent race conditions and duplicating efforts) There is currently no public use for this
178property.
179
180### File#analyzed
181
182A flag that helps mako know when a particular file has already been analyzed, so it doesn't
183continuously analyze the same file during subsequent builds. Do not change this manually,
184instead use `File#dirty()`.
185
186### File#isEntry()
187
188Short-hand for `tree.isEntry(file.path)`.
189
190### File#hasDependency(child)
191
192Short-hand for `tree.hasDependency(file.path, child)`.
193
194### File#addDependency(child)
195
196Short-hand for `tree.addDependency(file.path, child)`.
197
198### File#removeDependency(child)
199
200Short-hand for `tree.removeDependency(file.path, child)`.
201
202### File#dependencies([options])
203
204Short-hand for `tree.dependenciesOf(file.path, options)`.
205
206### File#dependants([options])
207
208Short-hand for `tree.dependantsOf(file.path, options)`.
209
210### File#dirty()
211
212Can be used by the `prewrite` hook to mark a file as "dirty" so that it should be analyzed again.
213
214For example, [mako-stat](http://github.com/makojs/stat) will use this method whenever the
215modification time for a file has changed, which indicates to mako that analyze needs to be run
216again for this file.
217
218### File#clone(tree)
219
220Returns a new `File` object that is an effective clone of the original.