Skip to content

Commit 9e823bd

Browse files
authored
Merge pull request #139 from ember-learn/refactor/remove-helper-items
[api] Remove helper items, rework navigation index
2 parents 7a295f4 + f80e066 commit 9e823bd

File tree

11 files changed

+188
-105
lines changed

11 files changed

+188
-105
lines changed

addon/components/api/x-class/template.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
<h1 class='docs-h1'>{{class.name}}</h1>
1+
<h1 class='docs-h1' data-test-class-name>{{class.name}}</h1>
22

33
{{! wrapping in a div seems to work around https://github.com/ember-learn/ember-cli-addon-docs/issues/7 }}
4-
<div>{{{class.description}}}</div>
4+
<div data-test-class-description>{{{class.description}}}</div>
55

66
{{#if hasContents}}
77
<div class="flex flex-row-reverse">

addon/components/api/x-component/template.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
<h1 class='docs-h1'>{{component.name}}</h1>
1+
<h1 class='docs-h1' data-test-component-name>{{component.name}}</h1>
22

33
{{! wrapping in a div seems to work around https://github.com/ember-learn/ember-cli-addon-docs/issues/7 }}
4-
<div>{{{component.description}}}</div>
4+
<div data-test-component-name>{{{component.description}}}</div>
55

66
{{#if hasContents}}
77
<div class="flex flex-row-reverse">

addon/components/api/x-module/template.hbs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
classes=module.classes
55
components=module.components
66
functions=module.functions
7-
helpers=module.helpers
87
variables=module.variables
98
)
109
}}
@@ -14,7 +13,6 @@
1413
classes=module.classes
1514
components=module.components
1615
functions=module.functions
17-
helpers=module.helpers
1816
variables=module.variables
1917
)
2018
}}

addon/models/module.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export default DS.Model.extend({
66
file: attr(),
77
variables: attr(),
88
functions: attr(),
9-
helpers: attr(),
109

1110
classes: hasMany('class', { async: false, }),
1211
components: hasMany('class', { async: false, })

lib/broccoli/docs-compiler.js

Lines changed: 50 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ function removeEmptyModules(modules) {
5757
module.classes.length === 0
5858
&& module.components.length === 0
5959
&& module.functions.length === 0
60-
&& module.helpers.length === 0
6160
&& module.variables.length === 0
6261
);
6362
});
@@ -137,99 +136,82 @@ function hoistDefaults(modules) {
137136
delete modules[m];
138137
}
139138
}
139+
140+
return modules;
140141
}
141142

142-
function generateResolvedTypedNavigationItems(collection, file, type) {
143-
return collection.filter(c => c.file.includes(`${type}s/`)).map((c) => {
144-
let segments = file.split('/');
143+
144+
145+
const RESOLVED_TYPES = [
146+
'components',
147+
'helpers',
148+
'controllers',
149+
'mixins',
150+
'models',
151+
'services'
152+
];
153+
154+
function generateResolvedTypeNavigationItems(modules, type) {
155+
let items = modules.map(m => {
156+
let segments = m.file.split('/');
145157
let fileName = segments.pop();
146158

147-
if (fileName === type) {
159+
if (type.match(fileName)) {
148160
fileName = segments.pop();
149161
}
150162

151163
let name;
152-
if (['component', 'helper'].includes(type)) {
164+
if (['components', 'helpers'].includes(type)) {
153165
name = `{{${fileName}}}`;
154166
} else {
155167
name = _.upperFirst(_.camelCase(fileName));
156168
}
157169

158170
return {
159-
path: `${type}s/${fileName}`,
171+
path: `${type}/${fileName}`,
160172
name
161173
};
162174
});
175+
176+
return _.sortBy(items, ['name']);
163177
}
164178

165-
function generateModuleNavigationItems(module, collection) {
166-
return collection.map((item) => {
167-
return {
168-
path: `root/${item.id || module.id}`,
169-
name: item.name,
170-
isDefault: item.exportType === 'default'
171-
};
172-
});
179+
function generateModuleNavigationItems(modules, type) {
180+
let navItems = modules.reduce((navItems, m) => {
181+
let items = m[type].map((item) => {
182+
return {
183+
path: `root/${item.id || module.id}`,
184+
name: item.name,
185+
isDefault: item.exportType === 'default'
186+
};
187+
});
188+
189+
if (items.length > 0) {
190+
navItems[m.file] = _.sortBy(items, ['name']);
191+
}
192+
193+
return navItems;
194+
}, {});
195+
196+
return hoistDefaults(navItems);
173197
}
174198

175199
function generateNavigationIndex(modules, klasses) {
176-
let components = [];
177-
let controllers = [];
178-
let helpers = [];
179-
let mixins = [];
180-
let models = [];
181-
let services = [];
182-
183-
let classes = {};
184-
let functions = {};
185-
let variables = {};
186-
187-
modules.forEach((m) => {
188-
let file = m.file;
189-
190-
let componentItems = generateResolvedTypedNavigationItems(m.components, file, 'component');
191-
let helperItems = generateResolvedTypedNavigationItems(m.helpers, file, 'helper');
192-
193-
let controllerItems = generateResolvedTypedNavigationItems(m.classes, file, 'controller');
194-
let mixinItems = generateResolvedTypedNavigationItems(m.classes, file, 'mixin');
195-
let modelItems = generateResolvedTypedNavigationItems(m.classes, file, 'model');
196-
let serviceItems = generateResolvedTypedNavigationItems(m.classes, file, 'service');
197-
198-
let classItems = generateModuleNavigationItems(
199-
m, m.classes.filter(c => !c.file.match(/controllers\/|mixins\/|models\/|services\//))
200-
);
200+
let navigationIndex = {};
201201

202-
let functionItems = generateModuleNavigationItems(m, m.functions);
203-
let variableItems = generateModuleNavigationItems(m, m.variables);
202+
for (let type of RESOLVED_TYPES) {
203+
let resolvedModules = modules.filter(m => m.file.match(`${type}/`) && !m.file.match('utils/'));
204204

205-
components = components.concat(componentItems);
206-
controllers = controllers.concat(controllerItems);
207-
helpers = helpers.concat(helperItems);
208-
mixins = mixins.concat(mixinItems);
209-
models = models.concat(modelItems);
210-
services = services.concat(serviceItems);
205+
navigationIndex[type] = generateResolvedTypeNavigationItems(resolvedModules, type);
206+
}
211207

212-
classes[file] = _.sortBy(classItems, ['name']);
213-
functions[file] = _.sortBy(functionItems, ['name']);
214-
variables[file] = _.sortBy(variableItems, ['name']);
215-
});
208+
let nonResolvedModules = modules.filter(m => {
209+
return !m.file.match(new RegExp(`(${RESOLVED_TYPES.join('|')})/`)) || m.file.match('utils/');
210+
})
216211

217-
hoistDefaults(classes);
218-
hoistDefaults(functions);
219-
hoistDefaults(variables);
220-
221-
let navigationIndex = {
222-
components: _.sortBy(components, ['path']),
223-
controllers: _.sortBy(controllers, ['name']),
224-
helpers: _.sortBy(helpers, ['path']),
225-
mixins: _.sortBy(mixins, ['name']),
226-
models: _.sortBy(models, ['name']),
227-
services: _.sortBy(services, ['name']),
228-
229-
classes,
230-
functions,
231-
variables
232-
};
212+
navigationIndex.classes = generateModuleNavigationItems(nonResolvedModules, 'classes');
213+
navigationIndex.functions = generateModuleNavigationItems(nonResolvedModules, 'functions');
214+
navigationIndex.variables = generateModuleNavigationItems(nonResolvedModules, 'variables');
233215

234216
for (let type in navigationIndex) {
235217
let items = navigationIndex[type];

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@
7979
"common-tags": "^1.7.2",
8080
"ember-classy-page-object": "^0.4.6",
8181
"ember-cli": "~3.0.0",
82-
"ember-cli-addon-docs-esdoc": "^0.1.1",
83-
"ember-cli-addon-docs-yuidoc": "^0.1.1",
82+
"ember-cli-addon-docs-esdoc": "^0.2.0",
83+
"ember-cli-addon-docs-yuidoc": "^0.2.0",
8484
"ember-cli-dependency-checker": "^2.1.0",
8585
"ember-cli-deploy": "^1.0.2",
8686
"ember-cli-deploy-build": "^1.1.1",
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/** @documenter esdoc */
2+
3+
import Helper from '@ember/component/helper';
4+
5+
/**
6+
A class based ESDoc helper
7+
*/
8+
export default class ESDocClassHelper extends Helper {
9+
/**
10+
returns the absolute value of a number
11+
12+
@param {number} [number] the passed number
13+
@return {number}
14+
*/
15+
compute([number]) {
16+
return Math.abs(number);
17+
}
18+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/** @documenter yuidoc */
2+
3+
import Helper from '@ember/component/helper';
4+
5+
/**
6+
A class based YUIDoc helper
7+
8+
@class YUIDocClassHelper
9+
*/
10+
const YUIDocClassHelper = Helper.extend({
11+
/**
12+
returns the absolute value of a number
13+
14+
@method compute
15+
@param {number} [number] the passed number
16+
@return {number}
17+
*/
18+
compute([number]) {
19+
return Math.abs(number);
20+
}
21+
});
22+
23+
export default YUIDocClassHelper;

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

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,78 @@ import { setupApplicationTest } from 'ember-qunit';
33
import { currentURL, visit } from '@ember/test-helpers';
44

55
import modulePage from '../../../pages/api/module';
6+
import classPage from '../../../pages/api/class';
67

78
module('Acceptance | API | helpers', function(hooks) {
89
setupApplicationTest(hooks);
910

10-
for (let documenter of ['esdoc', 'yuidoc']) {
11-
let helperName = `${documenter}Helper`;
12-
let kebabName = `${documenter}-helper`;
11+
module('standard helpers', function() {
12+
for (let documenter of ['esdoc', 'yuidoc']) {
13+
let helperName = `${documenter}Helper`;
14+
let kebabName = `${documenter}-helper`;
1315

14-
test('{{esdoc-helper}}', async function(assert) {
15-
await visit('/sandbox');
16-
await modulePage.navItems.findOne({ text: `{{${kebabName}}}` }).click();
16+
test(`{{${kebabName}}}`, async function(assert) {
17+
await visit('/sandbox');
18+
await modulePage.navItems.findOne({ text: `{{${kebabName}}}` }).click();
1719

18-
assert.equal(currentURL(), `/sandbox/api/helpers/${kebabName}`, 'correct url');
20+
assert.equal(currentURL(), `/sandbox/api/helpers/${kebabName}`, 'correct url');
1921

20-
let helpersSection = modulePage.sections.findOne({ header: 'Helpers' });
22+
let functionsSection = modulePage.sections.findOne({ header: 'Functions' });
2123

22-
assert.ok(helpersSection.isPresent, 'Renders the helpers section');
24+
assert.ok(functionsSection.isPresent, 'Renders the functions section');
2325

24-
let helperItem = helpersSection.items.findOne(i => i.header.includes(helperName));
26+
let helperItem = functionsSection.items.findOne(i => i.header.includes(helperName));
2527

26-
assert.ok(helperItem.isPresent, 'Renders the helper item');
28+
assert.ok(helperItem.isPresent, 'Renders the helper item');
2729

28-
assert.equal(
29-
helperItem.header,
30-
`${helperName}(number: number): number`,
31-
'renders the type signature of the helper correctly'
32-
);
30+
assert.equal(
31+
helperItem.header,
32+
`${helperName}(number: number): number`,
33+
'renders the type signature of the helper correctly'
34+
);
3335

34-
assert.equal(
35-
helperItem.importPath,
36-
`import { ${helperName} } from 'ember-cli-addon-docsapp/helpers/${kebabName}';`,
37-
'renders the import path correctly'
38-
);
36+
assert.equal(
37+
helperItem.importPath,
38+
`import { ${helperName} } from 'ember-cli-addon-docs/helpers/${kebabName}';`,
39+
'renders the import path correctly'
40+
);
3941

40-
assert.equal(helperItem.params.length, 1, 'renders the item parameter');
41-
});
42-
}
42+
assert.equal(helperItem.params.length, 1, 'renders the item parameter');
43+
});
44+
}
45+
});
46+
47+
module('class helpers', function() {
48+
for (let documenter of ['ESDoc', 'YUIDoc']) {
49+
let helperName = `${documenter}ClassHelper`;
50+
let kebabName = `${documenter.toLowerCase()}-class-helper`;
51+
52+
test(`{{${kebabName}}}`, async function(assert) {
53+
await visit('/sandbox');
54+
await classPage.navItems.findOne({ text: `{{${kebabName}}}` }).click();
55+
56+
assert.equal(currentURL(), `/sandbox/api/helpers/${kebabName}`, 'correct url');
57+
58+
assert.equal(classPage.title, helperName, 'Renders the class title correctly');
59+
60+
let methodsSection = modulePage.sections.findOne({ header: 'Methods' });
61+
62+
assert.ok(methodsSection.isPresent, 'Renders the methods section');
63+
64+
let computeItem = methodsSection.items.findOne(i => i.header.includes('compute'));
65+
66+
assert.ok(computeItem.isPresent, 'Renders the helper item');
67+
68+
assert.equal(
69+
computeItem.header,
70+
'compute(number: number): number',
71+
'renders the type signature of the helper correctly'
72+
);
73+
74+
assert.equal(computeItem.params.length, 1, 'renders the item parameter');
75+
});
76+
}
77+
});
4378
});
4479

4580

tests/pages/api/class.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import PageObject, { collection, text } from 'ember-classy-page-object';
2+
3+
const ClassPage = PageObject.extend({
4+
navItems: collection({ scope: '[data-test-id="nav-item"]' }),
5+
6+
title: text('[data-test-class-name]'),
7+
description: text('[data-test-class-description]'),
8+
9+
sections: collection({
10+
scope: '[data-test-api-section]',
11+
12+
header: text('[data-test-section-header]'),
13+
14+
items: collection({
15+
scope: '[data-test-item]',
16+
17+
header: text('[data-test-item-header]'),
18+
importPath: text('[data-test-import-path]'),
19+
description: text('[data-test-item-description]'),
20+
21+
params: collection({
22+
scope: '[data-test-item-params] [data-test-item-param]'
23+
})
24+
})
25+
})
26+
});
27+
28+
export default ClassPage.create();

0 commit comments

Comments
 (0)