Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions addon/components/api/x-class/template.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<h1 class='docs-h1'>{{class.name}}</h1>
<h1 class='docs-h1' data-test-class-name>{{class.name}}</h1>

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

{{#if hasContents}}
<div class="flex flex-row-reverse">
Expand Down
4 changes: 2 additions & 2 deletions addon/components/api/x-component/template.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<h1 class='docs-h1'>{{component.name}}</h1>
<h1 class='docs-h1' data-test-component-name>{{component.name}}</h1>

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

{{#if hasContents}}
<div class="flex flex-row-reverse">
Expand Down
2 changes: 0 additions & 2 deletions addon/components/api/x-module/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
classes=module.classes
components=module.components
functions=module.functions
helpers=module.helpers
variables=module.variables
)
}}
Expand All @@ -14,7 +13,6 @@
classes=module.classes
components=module.components
functions=module.functions
helpers=module.helpers
variables=module.variables
)
}}
Expand Down
1 change: 0 additions & 1 deletion addon/models/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export default DS.Model.extend({
file: attr(),
variables: attr(),
functions: attr(),
helpers: attr(),

classes: hasMany('class', { async: false, }),
components: hasMany('class', { async: false, })
Expand Down
118 changes: 50 additions & 68 deletions lib/broccoli/docs-compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ function removeEmptyModules(modules) {
module.classes.length === 0
&& module.components.length === 0
&& module.functions.length === 0
&& module.helpers.length === 0
&& module.variables.length === 0
);
});
Expand Down Expand Up @@ -137,99 +136,82 @@ function hoistDefaults(modules) {
delete modules[m];
}
}

return modules;
}

function generateResolvedTypedNavigationItems(collection, file, type) {
return collection.filter(c => c.file.includes(`${type}s/`)).map((c) => {
let segments = file.split('/');


const RESOLVED_TYPES = [
'components',
'helpers',
'controllers',
'mixins',
'models',
'services'
];

function generateResolvedTypeNavigationItems(modules, type) {
let items = modules.map(m => {
let segments = m.file.split('/');
let fileName = segments.pop();

if (fileName === type) {
if (type.match(fileName)) {
fileName = segments.pop();
}

let name;
if (['component', 'helper'].includes(type)) {
if (['components', 'helpers'].includes(type)) {
name = `{{${fileName}}}`;
} else {
name = _.upperFirst(_.camelCase(fileName));
}

return {
path: `${type}s/${fileName}`,
path: `${type}/${fileName}`,
name
};
});

return _.sortBy(items, ['name']);
}

function generateModuleNavigationItems(module, collection) {
return collection.map((item) => {
return {
path: `root/${item.id || module.id}`,
name: item.name,
isDefault: item.exportType === 'default'
};
});
function generateModuleNavigationItems(modules, type) {
let navItems = modules.reduce((navItems, m) => {
let items = m[type].map((item) => {
return {
path: `root/${item.id || module.id}`,
name: item.name,
isDefault: item.exportType === 'default'
};
});

if (items.length > 0) {
navItems[m.file] = _.sortBy(items, ['name']);
}

return navItems;
}, {});

return hoistDefaults(navItems);
}

function generateNavigationIndex(modules, klasses) {
let components = [];
let controllers = [];
let helpers = [];
let mixins = [];
let models = [];
let services = [];

let classes = {};
let functions = {};
let variables = {};

modules.forEach((m) => {
let file = m.file;

let componentItems = generateResolvedTypedNavigationItems(m.components, file, 'component');
let helperItems = generateResolvedTypedNavigationItems(m.helpers, file, 'helper');

let controllerItems = generateResolvedTypedNavigationItems(m.classes, file, 'controller');
let mixinItems = generateResolvedTypedNavigationItems(m.classes, file, 'mixin');
let modelItems = generateResolvedTypedNavigationItems(m.classes, file, 'model');
let serviceItems = generateResolvedTypedNavigationItems(m.classes, file, 'service');

let classItems = generateModuleNavigationItems(
m, m.classes.filter(c => !c.file.match(/controllers\/|mixins\/|models\/|services\//))
);
let navigationIndex = {};

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

components = components.concat(componentItems);
controllers = controllers.concat(controllerItems);
helpers = helpers.concat(helperItems);
mixins = mixins.concat(mixinItems);
models = models.concat(modelItems);
services = services.concat(serviceItems);
navigationIndex[type] = generateResolvedTypeNavigationItems(resolvedModules, type);
}

classes[file] = _.sortBy(classItems, ['name']);
functions[file] = _.sortBy(functionItems, ['name']);
variables[file] = _.sortBy(variableItems, ['name']);
});
let nonResolvedModules = modules.filter(m => {
return !m.file.match(new RegExp(`(${RESOLVED_TYPES.join('|')})/`)) || m.file.match('utils/');
})

hoistDefaults(classes);
hoistDefaults(functions);
hoistDefaults(variables);

let navigationIndex = {
components: _.sortBy(components, ['path']),
controllers: _.sortBy(controllers, ['name']),
helpers: _.sortBy(helpers, ['path']),
mixins: _.sortBy(mixins, ['name']),
models: _.sortBy(models, ['name']),
services: _.sortBy(services, ['name']),

classes,
functions,
variables
};
navigationIndex.classes = generateModuleNavigationItems(nonResolvedModules, 'classes');
navigationIndex.functions = generateModuleNavigationItems(nonResolvedModules, 'functions');
navigationIndex.variables = generateModuleNavigationItems(nonResolvedModules, 'variables');

for (let type in navigationIndex) {
let items = navigationIndex[type];
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@
"common-tags": "^1.7.2",
"ember-classy-page-object": "^0.4.6",
"ember-cli": "~3.0.0",
"ember-cli-addon-docs-esdoc": "^0.1.1",
"ember-cli-addon-docs-yuidoc": "^0.1.1",
"ember-cli-addon-docs-esdoc": "^0.2.0",
"ember-cli-addon-docs-yuidoc": "^0.2.0",
"ember-cli-dependency-checker": "^2.1.0",
"ember-cli-deploy": "^1.0.2",
"ember-cli-deploy-build": "^1.1.1",
Expand Down
18 changes: 18 additions & 0 deletions sandbox/app/helpers/esdoc-class-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** @documenter esdoc */

import Helper from '@ember/component/helper';

/**
A class based ESDoc helper
*/
export default class ESDocClassHelper extends Helper {
/**
returns the absolute value of a number

@param {number} [number] the passed number
@return {number}
*/
compute([number]) {
return Math.abs(number);
}
}
23 changes: 23 additions & 0 deletions sandbox/app/helpers/yuidoc-class-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/** @documenter yuidoc */

import Helper from '@ember/component/helper';

/**
A class based YUIDoc helper

@class YUIDocClassHelper
*/
const YUIDocClassHelper = Helper.extend({
/**
returns the absolute value of a number

@method compute
@param {number} [number] the passed number
@return {number}
*/
compute([number]) {
return Math.abs(number);
}
});

export default YUIDocClassHelper;
83 changes: 59 additions & 24 deletions tests/acceptance/sandbox/api/helpers-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,78 @@ import { setupApplicationTest } from 'ember-qunit';
import { currentURL, visit } from '@ember/test-helpers';

import modulePage from '../../../pages/api/module';
import classPage from '../../../pages/api/class';

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

for (let documenter of ['esdoc', 'yuidoc']) {
let helperName = `${documenter}Helper`;
let kebabName = `${documenter}-helper`;
module('standard helpers', function() {
for (let documenter of ['esdoc', 'yuidoc']) {
let helperName = `${documenter}Helper`;
let kebabName = `${documenter}-helper`;

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

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

let helpersSection = modulePage.sections.findOne({ header: 'Helpers' });
let functionsSection = modulePage.sections.findOne({ header: 'Functions' });

assert.ok(helpersSection.isPresent, 'Renders the helpers section');
assert.ok(functionsSection.isPresent, 'Renders the functions section');

let helperItem = helpersSection.items.findOne(i => i.header.includes(helperName));
let helperItem = functionsSection.items.findOne(i => i.header.includes(helperName));

assert.ok(helperItem.isPresent, 'Renders the helper item');
assert.ok(helperItem.isPresent, 'Renders the helper item');

assert.equal(
helperItem.header,
`${helperName}(number: number): number`,
'renders the type signature of the helper correctly'
);
assert.equal(
helperItem.header,
`${helperName}(number: number): number`,
'renders the type signature of the helper correctly'
);

assert.equal(
helperItem.importPath,
`import { ${helperName} } from 'ember-cli-addon-docsapp/helpers/${kebabName}';`,
'renders the import path correctly'
);
assert.equal(
helperItem.importPath,
`import { ${helperName} } from 'ember-cli-addon-docs/helpers/${kebabName}';`,
'renders the import path correctly'
);

assert.equal(helperItem.params.length, 1, 'renders the item parameter');
});
}
assert.equal(helperItem.params.length, 1, 'renders the item parameter');
});
}
});

module('class helpers', function() {
for (let documenter of ['ESDoc', 'YUIDoc']) {
let helperName = `${documenter}ClassHelper`;
let kebabName = `${documenter.toLowerCase()}-class-helper`;

test(`{{${kebabName}}}`, async function(assert) {
await visit('/sandbox');
await classPage.navItems.findOne({ text: `{{${kebabName}}}` }).click();

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

assert.equal(classPage.title, helperName, 'Renders the class title correctly');

let methodsSection = modulePage.sections.findOne({ header: 'Methods' });

assert.ok(methodsSection.isPresent, 'Renders the methods section');

let computeItem = methodsSection.items.findOne(i => i.header.includes('compute'));

assert.ok(computeItem.isPresent, 'Renders the helper item');

assert.equal(
computeItem.header,
'compute(number: number): number',
'renders the type signature of the helper correctly'
);

assert.equal(computeItem.params.length, 1, 'renders the item parameter');
});
}
});
});


28 changes: 28 additions & 0 deletions tests/pages/api/class.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import PageObject, { collection, text } from 'ember-classy-page-object';

const ClassPage = PageObject.extend({
navItems: collection({ scope: '[data-test-id="nav-item"]' }),

title: text('[data-test-class-name]'),
description: text('[data-test-class-description]'),

sections: collection({
scope: '[data-test-api-section]',

header: text('[data-test-section-header]'),

items: collection({
scope: '[data-test-item]',

header: text('[data-test-item-header]'),
importPath: text('[data-test-import-path]'),
description: text('[data-test-item-description]'),

params: collection({
scope: '[data-test-item-params] [data-test-item-param]'
})
})
})
});

export default ClassPage.create();
Loading