Skip to content

Commit e69e670

Browse files
authored
Merge pull request #166 from ember-learn/refactor/generalize-modules-links-and-api
[refactor] Simplify and generalize Module links
2 parents 7c4dbb8 + cf26502 commit e69e670

File tree

9 files changed

+66
-130
lines changed

9 files changed

+66
-130
lines changed
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import Component from '@ember/component';
22
import layout from './template';
3-
import config from 'dummy/config/environment';
4-
5-
const projectName = config['ember-cli-addon-docs'].projectName;
63

74
export default Component.extend({
85
layout,
9-
classNames: ['import-path'],
10-
projectName
6+
classNames: ['import-path']
117
});

addon/components/api/x-import-path/template.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
{{/if}}
88

99
<span class="hljs-keyword">from</span>
10-
<span class="hljs-string">'{{projectName}}{{item.file}}'</span>;
10+
<span class="hljs-string">'{{item.file}}'</span>;

addon/components/docs-viewer/x-nav-item/component.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ export default Component.extend({
1111

1212
didInsertElement() {
1313
this._super(...arguments);
14+
let model = this.get('model');
15+
16+
if (typeof model === 'string' && model.includes('#')) {
17+
return;
18+
}
1419

1520
next(() => {
1621
this.get('docsRoutes.items').addObject(this);

addon/components/docs-viewer/x-nav/template.hbs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@
4949
{{/each}}
5050
{{else}}
5151
{{#each-in items as |module items|}}
52-
<li class="docs-viewer__module-heading">
53-
{{module}}
54-
</li>
52+
{{subnav.item module
53+
(concat root '.api.item')
54+
(concat 'modules/' module)
55+
class="docs-viewer__module-heading"
56+
}}
5557

5658
{{#docs-viewer/x-nav-list as |subnav|}}
5759
{{#each items as |item|}}

addon/routes/docs/api/item.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,24 @@ export default Route.extend({
55
model({ path }) {
66
let item;
77

8-
if (path.match(/^root\//)) {
8+
if (path.match(/^modules\//)) {
99
// Find by fully qualified id
10-
let itemId = path.replace(/^root\//, '');
11-
let [moduleId] = itemId.split('~');
10+
let itemId = path.replace(/^modules\//, '');
11+
let [moduleId] = itemId.split(/~|#/);
1212

1313
let module = this.store.peekRecord('module', moduleId);
1414

1515
item = module.get('components').findBy('id', itemId)
1616
|| module.get('classes').findBy('id', itemId)
1717
|| module;
1818
} else {
19+
// Create a regex that will match modules by either the path, or the
20+
// pod-path (/component, /route, etc)
21+
let type = path.match(/^(.*)s\//)[1];
22+
let pathRegex = new RegExp(`${path}(/${type})?$`);
23+
1924
let modules = this.store.peekAll('module');
20-
let matches = modules.filter(m => m.id.match(path));
25+
let matches = modules.filter(m => m.id.match(pathRegex));
2126
let module = matches[0];
2227

2328
assert(`no modules match the path '${path}'`, matches.length > 0);

ember-cli-build.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
44
const Project = require('ember-cli/lib/models/project');
5+
const MergeTrees = require('broccoli-merge-trees');
6+
const Funnel = require('broccoli-funnel');
57

68
module.exports = function(defaults) {
79
let project = Project.closestSync(process.cwd());
@@ -21,9 +23,12 @@ module.exports = function(defaults) {
2123
},
2224
'ember-cli-addon-docs': {
2325
projects: {
24-
sandbox: {
25-
tree: 'sandbox'
26-
}
26+
sandbox: new MergeTrees([
27+
new Funnel('sandbox/app', { destDir: 'sandbox' }),
28+
new Funnel('sandbox', {
29+
include: ['package.json', 'README.md']
30+
})
31+
])
2732
}
2833
}
2934
});

index.js

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@ const EmberApp = require('ember-cli/lib/broccoli/ember-app'); // eslint-disable-
1010
const Plugin = require('broccoli-plugin');
1111
const walkSync = require('walk-sync');
1212

13-
const DEFAULT_PROJECTS = {
14-
main: {
15-
tree: null,
16-
include: null,
17-
includeTrees: ['addon']
18-
}
19-
}
20-
2113
module.exports = {
2214
name: 'ember-cli-addon-docs',
2315

@@ -95,7 +87,7 @@ module.exports = {
9587
}
9688

9789
this.addonOptions = Object.assign({}, includer.options['ember-cli-addon-docs']);
98-
this.addonOptions.projects = Object.assign({}, DEFAULT_PROJECTS, this.addonOptions.projects);
90+
this.addonOptions.projects = Object.assign({}, this.addonOptions.projects);
9991

10092
includer.options.includeFileExtensionInSnippetNames = includer.options.includeFileExtensionInSnippetNames || false;
10193
includer.options.snippetSearchPaths = includer.options.snippetSearchPaths || ['tests/dummy/app'];
@@ -182,35 +174,10 @@ module.exports = {
182174
let project = this.project;
183175
let docsTrees = [];
184176

185-
for (let projectName in this.addonOptions.projects) {
186-
let docProject = this.addonOptions.projects[projectName];
187-
188-
let addonSourceTree;
189-
190-
if (docProject.tree) {
191-
addonSourceTree = docProject.tree;
192-
} else {
193-
let include = docProject.include || [];
194-
let includeTrees = docProject.includeTrees || [];
195-
196-
let includeTreePaths = includeTrees.map(t => parentAddon.treePaths[t]);
197-
let includeFunnels = [
198-
// We need to be very careful to avoid triggering a watch on the addon root here
199-
// because of https://github.com/nodejs/node/issues/15683
200-
new Funnel(new UnwatchedDir(parentAddon.root), {
201-
include: ['package.json', 'README.md']
202-
})
203-
];
204-
205-
for (let path of include.concat(includeTreePaths)) {
206-
let fullPath = `${parentAddon.root}/${path}`;
207-
if (fs.existsSync(fullPath)) {
208-
includeFunnels.push(new Funnel(fullPath, { destDir: path }));
209-
}
210-
}
177+
this.addonOptions.projects.main = this.addonOptions.projects.main || generateDefaultProject(parentAddon);
211178

212-
addonSourceTree = new MergeTrees(includeFunnels);
213-
}
179+
for (let projectName in this.addonOptions.projects) {
180+
let addonSourceTree = this.addonOptions.projects[projectName];
214181

215182
let pluginRegistry = new PluginRegistry(project);
216183

@@ -279,6 +246,33 @@ function findImporter(addon) {
279246
}
280247
}
281248

249+
function generateDefaultProject(parentAddon) {
250+
let includeFunnels = [
251+
// We need to be very careful to avoid triggering a watch on the addon root here
252+
// because of https://github.com/nodejs/node/issues/15683
253+
new Funnel(new UnwatchedDir(parentAddon.root), {
254+
include: ['package.json', 'README.md']
255+
})
256+
];
257+
258+
let addonTreePath = path.join(parentAddon.root, parentAddon.treePaths['addon']);
259+
let testSupportPath = path.join(parentAddon.root, parentAddon.treePaths['addon-test-support']);
260+
261+
if (fs.existsSync(addonTreePath)) {
262+
includeFunnels.push(new Funnel(addonTreePath, {
263+
destDir: parentAddon.name
264+
}));
265+
}
266+
267+
if (fs.existsSync(testSupportPath)) {
268+
includeFunnels.push(new Funnel(testSupportPath, {
269+
destDir: `${parentAddon.name}/test-support`
270+
}));
271+
}
272+
273+
return new MergeTrees(includeFunnels);
274+
}
275+
282276
class FindDummyAppFiles extends Plugin {
283277
build() {
284278
let addonPath = this.inputPaths[0];

lib/broccoli/docs-compiler.js

Lines changed: 5 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -72,76 +72,6 @@ function compileDocDescriptions(modules) {
7272
});
7373
}
7474

75-
function stripAppAddonDirs(modules) {
76-
77-
modules.forEach((module) => {
78-
module.file = module.file.replace(/^(app|addon)/, '');
79-
});
80-
81-
eachRelationship(modules, (relationship) => {
82-
relationship.forEach((item) => {
83-
if (item.file) item.file = item.file.replace(/^(app|addon)/, '');
84-
if (item.name) item.name = item.name.replace(/^(app|addon)/, '');
85-
});
86-
});
87-
}
88-
89-
/**
90-
* "Hoists" default exports from a given module. This is particularly useful
91-
* for class files, which generally only export a single default class and
92-
* would normally look like this:
93-
*
94-
* /classes/foo
95-
* FooClass
96-
* /classes/bar
97-
* BarClass
98-
*
99-
* Instead they become this:
100-
*
101-
* /classes
102-
* FooClass
103-
* BarClass
104-
*
105-
* Since these are the only exports of that type and the default, users can
106-
* generally infer that they can import the class from the file with the same
107-
* name as the class or component (in many cases this also doesn't matter
108-
* since the affected classes will be resolved).
109-
*
110-
* If a file has named exports they will continue to appear in that module:
111-
*
112-
* /classes
113-
* FooClass
114-
* /classes/foo
115-
* HelperClass
116-
*
117-
* @param {Object} modules
118-
*/
119-
function hoistDefaults(modules) {
120-
for (let m in modules) {
121-
let module = modules[m];
122-
let parentModulePath = path.dirname(m);
123-
124-
let value = _.remove(module, { isDefault: true });
125-
126-
if (value) {
127-
modules[parentModulePath] = (modules[parentModulePath] || []).concat(value);
128-
}
129-
}
130-
131-
// Remove any modules without exports now that hoisting is done
132-
for (let m in modules) {
133-
let module = modules[m];
134-
135-
if (module.length === 0) {
136-
delete modules[m];
137-
}
138-
}
139-
140-
return modules;
141-
}
142-
143-
144-
14575
const RESOLVED_TYPES = [
14676
'components',
14777
'helpers',
@@ -177,23 +107,23 @@ function generateResolvedTypeNavigationItems(modules, type) {
177107
}
178108

179109
function generateModuleNavigationItems(modules, type) {
180-
let navItems = modules.reduce((navItems, m) => {
110+
return modules.reduce((navItems, m) => {
181111
let items = m[type].map((item) => {
112+
let path = item.id ? item.id : `${m.id}#${item.name}`;
113+
182114
return {
183-
path: `root/${item.id || m.id}`,
115+
path: `modules/${path}`,
184116
name: item.name,
185117
isDefault: item.exportType === 'default'
186118
};
187119
});
188120

189121
if (items.length > 0) {
190-
navItems[m.file] = _.sortBy(items, ['name']);
122+
navItems[m.file] = _.sortBy(items, ['name']);
191123
}
192124

193125
return navItems;
194126
}, {});
195-
196-
return hoistDefaults(navItems);
197127
}
198128

199129
function generateNavigationIndex(modules, klasses) {
@@ -255,7 +185,6 @@ module.exports = class DocsCompiler extends CachingWriter {
255185
removeHiddenDocs(modules);
256186
removeEmptyModules(modules);
257187
compileDocDescriptions(modules);
258-
stripAppAddonDirs(modules);
259188

260189
let project = {
261190
id: name,

tests/acceptance/sandbox/api/helpers-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module('Acceptance | API | helpers', function(hooks) {
3737

3838
assert.equal(
3939
helperItem.importPath,
40-
`import { ${helperName} } from 'ember-cli-addon-docs/helpers/${kebabName}';`,
40+
`import { ${helperName} } from 'sandbox/helpers/${kebabName}';`,
4141
'renders the import path correctly'
4242
);
4343

0 commit comments

Comments
 (0)