build(docs-infra): error guides in docs (#40060)
add /errors to docs create formatting for error guides infra PR Close #40060
This commit is contained in:
parent
10994ae68c
commit
fbfd4889a9
|
@ -1232,6 +1232,7 @@ groups:
|
||||||
'goldens/public-api/**',
|
'goldens/public-api/**',
|
||||||
'CHANGELOG.md',
|
'CHANGELOG.md',
|
||||||
'docs/NAMING.md',
|
'docs/NAMING.md',
|
||||||
|
'aio/content/errors/*.md',
|
||||||
'aio/content/guide/glossary.md',
|
'aio/content/guide/glossary.md',
|
||||||
'aio/content/guide/styleguide.md',
|
'aio/content/guide/styleguide.md',
|
||||||
'aio/content/examples/styleguide/**',
|
'aio/content/examples/styleguide/**',
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
# Errors List
|
|
@ -56,35 +56,35 @@
|
||||||
"tooltip": "Set up your environment and learn basic concepts",
|
"tooltip": "Set up your environment and learn basic concepts",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"title": "Try it",
|
"title": "Try it",
|
||||||
"tooltip": "Examine and work with a ready-made sample app, with no setup.",
|
"tooltip": "Examine and work with a ready-made sample app, with no setup.",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"url": "start",
|
"url": "start",
|
||||||
"title": "Getting started",
|
"title": "Getting started",
|
||||||
"tooltip": "Take a look at Angular's component model, template syntax, and component communication."
|
"tooltip": "Take a look at Angular's component model, template syntax, and component communication."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "start/start-routing",
|
"url": "start/start-routing",
|
||||||
"title": "Adding navigation",
|
"title": "Adding navigation",
|
||||||
"tooltip": "Navigate among different page views using the browser's URL."
|
"tooltip": "Navigate among different page views using the browser's URL."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "start/start-data",
|
"url": "start/start-data",
|
||||||
"title": "Managing Data",
|
"title": "Managing Data",
|
||||||
"tooltip": "Use services and access external data via HTTP."
|
"tooltip": "Use services and access external data via HTTP."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "start/start-forms",
|
"url": "start/start-forms",
|
||||||
"title": "Using Forms for User Input",
|
"title": "Using Forms for User Input",
|
||||||
"tooltip": "Learn about fetching and managing data from users with forms."
|
"tooltip": "Learn about fetching and managing data from users with forms."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "start/start-deployment",
|
"url": "start/start-deployment",
|
||||||
"title": "Deploying an application",
|
"title": "Deploying an application",
|
||||||
"tooltip": "Move to local development, or deploy your application to Firebase or your own server."
|
"tooltip": "Move to local development, or deploy your application to Firebase or your own server."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "guide/setup-local",
|
"url": "guide/setup-local",
|
||||||
|
@ -916,6 +916,17 @@
|
||||||
"tooltip": "Details of the Angular packages, classes, interfaces, and other types.",
|
"tooltip": "Details of the Angular packages, classes, interfaces, and other types.",
|
||||||
"url": "api"
|
"url": "api"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "Error Reference",
|
||||||
|
"tooltip": "Details of the errors that can be thrown by Angular.",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"title": "Overview",
|
||||||
|
"url": "errors",
|
||||||
|
"hidden": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "Example applications",
|
"title": "Example applications",
|
||||||
"tooltip": "List of all of the example applications in the Angular documentation.",
|
"tooltip": "List of all of the example applications in the Angular documentation.",
|
||||||
|
|
|
@ -52,6 +52,7 @@ aio-shell.folder-api mat-toolbar.mat-toolbar,
|
||||||
aio-shell.folder-cli mat-toolbar.mat-toolbar,
|
aio-shell.folder-cli mat-toolbar.mat-toolbar,
|
||||||
aio-shell.folder-docs mat-toolbar.mat-toolbar,
|
aio-shell.folder-docs mat-toolbar.mat-toolbar,
|
||||||
aio-shell.folder-guide mat-toolbar.mat-toolbar,
|
aio-shell.folder-guide mat-toolbar.mat-toolbar,
|
||||||
|
aio-shell.folder-errors mat-toolbar.mat-toolbar,
|
||||||
aio-shell.folder-start mat-toolbar.mat-toolbar,
|
aio-shell.folder-start mat-toolbar.mat-toolbar,
|
||||||
aio-shell.folder-tutorial mat-toolbar.mat-toolbar {
|
aio-shell.folder-tutorial mat-toolbar.mat-toolbar {
|
||||||
@media (min-width: $showTopMenuWidth) {
|
@media (min-width: $showTopMenuWidth) {
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
|
||||||
|
.error-list {
|
||||||
|
display: grid;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
margin: 0 0 0 -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
@include font-size(14);
|
||||||
|
margin: 8px 0;
|
||||||
|
@include line-height(14);
|
||||||
|
padding: 0;
|
||||||
|
float: left;
|
||||||
|
overflow: hidden;
|
||||||
|
min-width: 220px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.symbol {
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
&.runtime {
|
||||||
|
background: $green-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.compiler {
|
||||||
|
background: $blue-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.symbol.runtime:before {
|
||||||
|
content: "R";
|
||||||
|
}
|
||||||
|
|
||||||
|
.symbol.compiler:before {
|
||||||
|
content: "C";
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $blue-grey-600;
|
||||||
|
display: inline-block;
|
||||||
|
@include line-height(16);
|
||||||
|
padding: 0 16px 0;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all .3s;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $blue-grey-50;
|
||||||
|
color: $blue-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
@import 'deploy-theme';
|
@import 'deploy-theme';
|
||||||
@import 'details';
|
@import 'details';
|
||||||
@import 'edit-page-cta';
|
@import 'edit-page-cta';
|
||||||
|
@import 'errors';
|
||||||
@import 'features';
|
@import 'features';
|
||||||
@import 'filetree';
|
@import 'filetree';
|
||||||
@import 'heading-anchors';
|
@import 'heading-anchors';
|
||||||
|
|
|
@ -17,7 +17,6 @@ module.exports =
|
||||||
// Register the processors
|
// Register the processors
|
||||||
.processor(require('./processors/mergeParameterInfo'))
|
.processor(require('./processors/mergeParameterInfo'))
|
||||||
.processor(require('./processors/processPseudoClasses'))
|
.processor(require('./processors/processPseudoClasses'))
|
||||||
.processor(require('./processors/splitDescription'))
|
|
||||||
.processor(require('./processors/convertPrivateClassesToInterfaces'))
|
.processor(require('./processors/convertPrivateClassesToInterfaces'))
|
||||||
.processor(require('./processors/generateApiListDoc'))
|
.processor(require('./processors/generateApiListDoc'))
|
||||||
.processor(require('./processors/addNotYetDocumentedProperty'))
|
.processor(require('./processors/addNotYetDocumentedProperty'))
|
||||||
|
|
|
@ -32,6 +32,7 @@ module.exports = new Package('angular-base', [
|
||||||
.processor(require('./processors/copyContentAssets'))
|
.processor(require('./processors/copyContentAssets'))
|
||||||
.processor(require('./processors/renderLinkInfo'))
|
.processor(require('./processors/renderLinkInfo'))
|
||||||
.processor(require('./processors/checkContentRules'))
|
.processor(require('./processors/checkContentRules'))
|
||||||
|
.processor(require('./processors/splitDescription'))
|
||||||
|
|
||||||
// overrides base packageInfo and returns the one for the 'angular/angular' repo.
|
// overrides base packageInfo and returns the one for the 'angular/angular' repo.
|
||||||
.factory('packageInfo', function() { return require(path.resolve(PROJECT_ROOT, 'package.json')); })
|
.factory('packageInfo', function() { return require(path.resolve(PROJECT_ROOT, 'package.json')); })
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google LLC All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
const path = require('canonical-path');
|
||||||
|
const Package = require('dgeni').Package;
|
||||||
|
const basePackage = require('../angular-base-package');
|
||||||
|
const contentPackage = require('../content-package');
|
||||||
|
const {CONTENTS_PATH, TEMPLATES_PATH, requireFolder} = require('../config');
|
||||||
|
|
||||||
|
const errorPackage = new Package('angular-errors', [basePackage, contentPackage]);
|
||||||
|
errorPackage.factory(require('./readers/error'))
|
||||||
|
.processor(require('./processors/processErrorDocs'))
|
||||||
|
.processor(require('./processors/processErrorsContainerDoc'))
|
||||||
|
|
||||||
|
// Where do we find the error documentation files?
|
||||||
|
.config(function(readFilesProcessor, errorFileReader) {
|
||||||
|
readFilesProcessor.fileReaders.push(errorFileReader);
|
||||||
|
readFilesProcessor.sourceFiles = readFilesProcessor.sourceFiles.concat([
|
||||||
|
{
|
||||||
|
basePath: CONTENTS_PATH,
|
||||||
|
include: CONTENTS_PATH + '/errors/**/*.md',
|
||||||
|
exclude: CONTENTS_PATH + '/errors/index.md',
|
||||||
|
fileReader: 'errorFileReader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
basePath: CONTENTS_PATH,
|
||||||
|
include: CONTENTS_PATH + '/errors/index.md',
|
||||||
|
fileReader: 'contentFileReader'
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
// Here we compute the `id`, `code`, `aliases`, `path` and `outputPath` for the `error` docs.
|
||||||
|
// * The `id` is the same as the `path` (the source path with the `.md` stripped off).
|
||||||
|
// * The `code` is the id without any containing paths (currently all errors must be on the top
|
||||||
|
// level).
|
||||||
|
// * The `aliases` are used for automatic code linking and search terms.
|
||||||
|
.config(function(computeIdsProcessor, computePathsProcessor) {
|
||||||
|
computeIdsProcessor.idTemplates.push({
|
||||||
|
docTypes: ['error'],
|
||||||
|
getId: function(doc) {
|
||||||
|
return doc.fileInfo
|
||||||
|
.relativePath
|
||||||
|
// strip off the extension
|
||||||
|
.replace(/\.\w*$/, '');
|
||||||
|
},
|
||||||
|
getAliases: function(doc) {
|
||||||
|
doc.code = path.basename(doc.id);
|
||||||
|
return [doc.id, doc.code];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
computePathsProcessor.pathTemplates = computePathsProcessor.pathTemplates.concat([
|
||||||
|
{
|
||||||
|
docTypes: ['error'],
|
||||||
|
getPath: (doc) => doc.id,
|
||||||
|
outputPathTemplate: '${path}.json',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
// Configure jsdoc-style tag parsing
|
||||||
|
.config(function(parseTagsProcessor, getInjectables) {
|
||||||
|
// Load up all the tag definitions in the tag-defs folder
|
||||||
|
parseTagsProcessor.tagDefinitions = parseTagsProcessor.tagDefinitions.concat(
|
||||||
|
getInjectables(requireFolder(__dirname, './tag-defs')));
|
||||||
|
})
|
||||||
|
|
||||||
|
// The templates that define how the `error` and `error-container` doc-types are rendered are
|
||||||
|
// found in the `TEMPLATES_PATH/error` directory.
|
||||||
|
.config(function(templateFinder) {
|
||||||
|
templateFinder.templateFolders.unshift(path.resolve(TEMPLATES_PATH, 'error'));
|
||||||
|
})
|
||||||
|
|
||||||
|
// The AIO application expects content files to be provided as JSON files that it requests via
|
||||||
|
// HTTP. So here we tell the `convertToJsonProcessor` to include docs of type `error` in those
|
||||||
|
// that it converts.
|
||||||
|
.config(function(convertToJsonProcessor, postProcessHtml) {
|
||||||
|
convertToJsonProcessor.docTypes.push('error');
|
||||||
|
postProcessHtml.docTypes.push('error');
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = errorPackage;
|
|
@ -0,0 +1,55 @@
|
||||||
|
module.exports = function processErrorDocs(createDocMessage) {
|
||||||
|
return {
|
||||||
|
$runAfter: ['extra-docs-added'],
|
||||||
|
$runBefore: ['rendering-docs'],
|
||||||
|
$process(docs) {
|
||||||
|
const navigationDoc = docs.find(doc => doc.docType === 'navigation-json');
|
||||||
|
const errorsNode = navigationDoc && findErrorsNode(navigationDoc.data['SideNav']);
|
||||||
|
|
||||||
|
if (!errorsNode) {
|
||||||
|
throw new Error(createDocMessage(
|
||||||
|
'Missing `errors` url - This node is needed as a place to insert the generated errors docs.',
|
||||||
|
navigationDoc));
|
||||||
|
}
|
||||||
|
|
||||||
|
docs.forEach(doc => {
|
||||||
|
if (doc.docType === 'error') {
|
||||||
|
// Add to navigation doc
|
||||||
|
const title = `${doc.code}: ${doc.name}`;
|
||||||
|
errorsNode.children.push({url: doc.path, title: title, tooltip: doc.name});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look for the `errors` navigation node. It is the node whose first child has `url: 'errors'`.
|
||||||
|
* (NOTE: Using the URL instead of the title, because it is more robust.)
|
||||||
|
*
|
||||||
|
* We will "recursively" check all navigation nodes and their children (in breadth-first order),
|
||||||
|
* until we find the `errors` node. Keep a list of nodes lists to check.
|
||||||
|
* (NOTE: Each item in the list is a LIST of nodes.)
|
||||||
|
*/
|
||||||
|
function findErrorsNode(nodes) {
|
||||||
|
const nodesList = [nodes];
|
||||||
|
|
||||||
|
while (nodesList.length > 0) {
|
||||||
|
// Get the first item from the list of nodes lists.
|
||||||
|
const currentNodes = nodesList.shift();
|
||||||
|
const errorsNode = currentNodes.find(isErrorsNode);
|
||||||
|
|
||||||
|
// One of the nodes in `currentNodes` was the `errors` node. Return it.
|
||||||
|
if (errorsNode) return errorsNode;
|
||||||
|
|
||||||
|
// The `errors` node is not in `currentNodes`. Check each node's children (if any).
|
||||||
|
currentNodes.forEach(node => node.children && nodesList.push(node.children));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We checked all navigation nodes and their children and did not find the `errors` node.
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isErrorsNode(node) {
|
||||||
|
return node.children && node.children.length && node.children[0].url === 'errors';
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
const testPackage = require('../../helpers/test-package');
|
||||||
|
const Dgeni = require('dgeni');
|
||||||
|
|
||||||
|
describe('processErrorDocs processor', () => {
|
||||||
|
let dgeni, injector, processor, createDocMessage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
dgeni = new Dgeni([testPackage('angular-errors-package')]);
|
||||||
|
injector = dgeni.configureInjector();
|
||||||
|
processor = injector.get('processErrorDocs');
|
||||||
|
createDocMessage = injector.get('createDocMessage');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be available on the injector', () => {
|
||||||
|
expect(processor.$process).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run after the correct processor', () => {
|
||||||
|
expect(processor.$runAfter).toEqual(['extra-docs-added']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run before the correct processor', () => {
|
||||||
|
expect(processor.$runBefore).toEqual(['rendering-docs']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add the error to the `errors` node in the navigation doc if there is a top level node with a `errors` url',
|
||||||
|
() => {
|
||||||
|
const errorDoc = {
|
||||||
|
docType: 'error',
|
||||||
|
name: 'error1',
|
||||||
|
code: '888',
|
||||||
|
path: 'errors/error1',
|
||||||
|
};
|
||||||
|
const navigation = {
|
||||||
|
docType: 'navigation-json',
|
||||||
|
data: {
|
||||||
|
SideNav: [
|
||||||
|
{url: 'some/page', title: 'Some Page'},
|
||||||
|
{
|
||||||
|
title: 'Errors',
|
||||||
|
children: [{'title': 'Overview', 'url': 'errors'}],
|
||||||
|
},
|
||||||
|
{url: 'other/page', title: 'Other Page'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
processor.$process([errorDoc, navigation]);
|
||||||
|
expect(navigation.data.SideNav[1].title).toEqual('Errors');
|
||||||
|
expect(navigation.data.SideNav[1].children).toEqual([
|
||||||
|
{url: 'errors', title: 'Overview'},
|
||||||
|
{url: 'errors/error1', title: '888: error1', tooltip: 'error1'},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect the `errors` node if it is nested in another node', () => {
|
||||||
|
const errorDoc = {
|
||||||
|
docType: 'error',
|
||||||
|
name: 'error1',
|
||||||
|
code: '888',
|
||||||
|
path: 'errors/error1',
|
||||||
|
};
|
||||||
|
const navigation = {
|
||||||
|
docType: 'navigation-json',
|
||||||
|
data: {
|
||||||
|
SideNav: [
|
||||||
|
{url: 'some/page', title: 'Some Page'},
|
||||||
|
{
|
||||||
|
title: 'Errors Grandparent',
|
||||||
|
children: [
|
||||||
|
{url: 'some/nested/page', title: 'Some Nested Page'},
|
||||||
|
{
|
||||||
|
title: 'Errors Parent',
|
||||||
|
children: [
|
||||||
|
{url: 'some/more/nested/page', title: 'Some More Nested Page'},
|
||||||
|
{
|
||||||
|
title: 'Errors',
|
||||||
|
children: [{'title': 'Overview', 'url': 'errors'}],
|
||||||
|
},
|
||||||
|
{url: 'other/more/nested/page', title: 'Other More Nested Page'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{url: 'other/nested/page', title: 'Other Nested Page'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{url: 'other/page', title: 'Other Page'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
processor.$process([errorDoc, navigation]);
|
||||||
|
|
||||||
|
const errorsContainerNode = navigation.data.SideNav[1].children[1].children[1];
|
||||||
|
expect(errorsContainerNode.title).toEqual('Errors');
|
||||||
|
expect(errorsContainerNode.children).toEqual([
|
||||||
|
{url: 'errors', title: 'Overview'},
|
||||||
|
{url: 'errors/error1', title: '888: error1', tooltip: 'error1'},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should complain if there is no child with `errors` url', () => {
|
||||||
|
const errorDoc = {
|
||||||
|
docType: 'error',
|
||||||
|
name: 'error1',
|
||||||
|
code: '888',
|
||||||
|
path: 'errors/error1',
|
||||||
|
};
|
||||||
|
const navigation = {
|
||||||
|
docType: 'navigation-json',
|
||||||
|
data: {
|
||||||
|
SideNav: [
|
||||||
|
{url: 'some/page', title: 'Some Page'}, {
|
||||||
|
title: 'Errors',
|
||||||
|
tooltip: 'Angular Error reference',
|
||||||
|
children: [{'title': 'Overview', 'url': 'not-errors'}]
|
||||||
|
},
|
||||||
|
{url: 'other/page', title: 'Other Page'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(() => processor.$process([errorDoc, navigation]))
|
||||||
|
.toThrowError(createDocMessage(
|
||||||
|
'Missing `errors` url - This node is needed as a place to insert the generated errors docs.',
|
||||||
|
navigation));
|
||||||
|
});
|
||||||
|
});
|
11
aio/tools/transforms/angular-errors-package/processors/processErrorsContainerDoc.js
vendored
Normal file
11
aio/tools/transforms/angular-errors-package/processors/processErrorsContainerDoc.js
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
module.exports = function processErrorsContainerDoc() {
|
||||||
|
return {
|
||||||
|
$runAfter: ['extra-docs-added'],
|
||||||
|
$runBefore: ['rendering-docs'],
|
||||||
|
$process(docs) {
|
||||||
|
const errorsDoc = docs.find(doc => doc.id === 'errors/index');
|
||||||
|
errorsDoc.id = 'errors-container';
|
||||||
|
errorsDoc.errors = docs.filter(doc => doc.docType === 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,22 @@
|
||||||
|
const testPackage = require('../../helpers/test-package');
|
||||||
|
const processorFactory = require('./processErrorsContainerDoc');
|
||||||
|
const Dgeni = require('dgeni');
|
||||||
|
|
||||||
|
describe('processErrorsContainerDoc processor', () => {
|
||||||
|
it('should be available on the injector', () => {
|
||||||
|
const dgeni = new Dgeni([testPackage('angular-errors-package')]);
|
||||||
|
const injector = dgeni.configureInjector();
|
||||||
|
const processor = injector.get('processErrorsContainerDoc');
|
||||||
|
expect(processor.$process).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run after the correct processor', () => {
|
||||||
|
const processor = processorFactory();
|
||||||
|
expect(processor.$runAfter).toEqual(['extra-docs-added']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run before the correct processor', () => {
|
||||||
|
const processor = processorFactory();
|
||||||
|
expect(processor.$runBefore).toEqual(['rendering-docs']);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* @dgService
|
||||||
|
* @description
|
||||||
|
* This file reader will pull the contents from a text file (by default .md)
|
||||||
|
*
|
||||||
|
* The doc will initially have the form:
|
||||||
|
* ```
|
||||||
|
* {
|
||||||
|
* docType: 'error',
|
||||||
|
* content: 'the content of the file',
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
module.exports = function errorFileReader() {
|
||||||
|
return {
|
||||||
|
name: 'errorFileReader',
|
||||||
|
defaultPattern: /\.md$/,
|
||||||
|
getDocs: function(fileInfo) {
|
||||||
|
// We return a single element array because content files only contain one document
|
||||||
|
return [{docType: 'error', content: fileInfo.content}];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,44 @@
|
||||||
|
const Dgeni = require('dgeni');
|
||||||
|
const path = require('canonical-path');
|
||||||
|
const testPackage = require('../../helpers/test-package');
|
||||||
|
|
||||||
|
describe('errorFileReader', () => {
|
||||||
|
let dgeni, injector, fileReader;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
dgeni = new Dgeni([testPackage('angular-errors-package', false)]);
|
||||||
|
injector = dgeni.configureInjector();
|
||||||
|
fileReader = injector.get('errorFileReader');
|
||||||
|
});
|
||||||
|
|
||||||
|
function createFileInfo(file, content, basePath) {
|
||||||
|
return {
|
||||||
|
fileReader: fileReader.name,
|
||||||
|
filePath: file,
|
||||||
|
baseName: path.basename(file, path.extname(file)),
|
||||||
|
extension: path.extname(file).replace(/^\./, ''),
|
||||||
|
basePath: basePath,
|
||||||
|
relativePath: path.relative(basePath, file),
|
||||||
|
content: content
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('defaultPattern', () => {
|
||||||
|
it('should match .md files', () => {
|
||||||
|
expect(fileReader.defaultPattern.test('abc.md')).toBeTruthy();
|
||||||
|
expect(fileReader.defaultPattern.test('abc.js')).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('getDocs', () => {
|
||||||
|
it('should return an object containing info about the file and its contents', () => {
|
||||||
|
const fileInfo = createFileInfo(
|
||||||
|
'project/path/modules/someModule/foo/docs/subfolder/bar.md', 'A load of content',
|
||||||
|
'project/path');
|
||||||
|
expect(fileReader.getDocs(fileInfo)).toEqual([
|
||||||
|
{docType: 'error', content: 'A load of content'}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = function() {
|
||||||
|
return {name: 'category'};
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = function() {
|
||||||
|
return {name: 'debugging'};
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = function() {
|
||||||
|
return {name: 'shortDescription'};
|
||||||
|
};
|
|
@ -9,12 +9,13 @@ const Package = require('dgeni').Package;
|
||||||
const gitPackage = require('dgeni-packages/git');
|
const gitPackage = require('dgeni-packages/git');
|
||||||
const apiPackage = require('../angular-api-package');
|
const apiPackage = require('../angular-api-package');
|
||||||
const contentPackage = require('../angular-content-package');
|
const contentPackage = require('../angular-content-package');
|
||||||
|
const errorsPackage = require('../angular-errors-package');
|
||||||
const cliDocsPackage = require('../cli-docs-package');
|
const cliDocsPackage = require('../cli-docs-package');
|
||||||
const { extname, resolve } = require('canonical-path');
|
const { extname, resolve } = require('canonical-path');
|
||||||
const { existsSync } = require('fs');
|
const { existsSync } = require('fs');
|
||||||
const { SRC_PATH } = require('../config');
|
const { SRC_PATH } = require('../config');
|
||||||
|
|
||||||
module.exports = new Package('angular.io', [gitPackage, apiPackage, contentPackage, cliDocsPackage])
|
module.exports = new Package('angular.io', [gitPackage, apiPackage, contentPackage, cliDocsPackage, errorsPackage])
|
||||||
|
|
||||||
// This processor relies upon the versionInfo. See below...
|
// This processor relies upon the versionInfo. See below...
|
||||||
.processor(require('./processors/processNavigationMap'))
|
.processor(require('./processors/processNavigationMap'))
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{% import "lib/githubLinks.html" as github -%}
|
||||||
|
|
||||||
|
<h1>{$ doc.code $}: {$ doc.shortDescription $}</h1>
|
||||||
|
<div class="github-links">
|
||||||
|
{$ github.githubEditLink(doc, versionInfo) $}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="content">
|
||||||
|
<h2>Description</h2>
|
||||||
|
{$ doc.description | marked $}
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="debugging">
|
||||||
|
<h2>Debugging the error</h2>
|
||||||
|
{$ doc.debugging | marked $}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends 'content.template.html' -%}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="content">
|
||||||
|
{$ doc.description | marked $}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="error-list">
|
||||||
|
{% for error in doc.errors %}
|
||||||
|
<li>
|
||||||
|
<a class="code-anchor" href="{$ error.path $}">
|
||||||
|
<span class="symbol {$ error.category $}"></span>
|
||||||
|
<code class="no-auto-link">{$ error.code $}: {$ error.name $}</code>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue