build(aio): big move of docs related files (#14361)

All the docs related files (docs-app, doc-gen, content, etc)
are now to be found inside the `/aio` folder.

The related gulp tasks have been moved from the top level
gulp file to a new one inside the `/aio` folder.

The structure of the `/aio` folder now looks like:

```
/aio/
  build/         # gulp tasks
  content/       #MARKDOWN FILES for devguides, cheatsheet, etc
    devguides/
    cheatsheets/
  transforms/    #dgeni packages, templates, etc
  src/
    app/
    assets/
    content/    #HTML + JSON build artifacts produced by dgeni from /aio/content.
                #This dir is .gitignored-ed
  e2e/           #protractor tests for the doc viewer app
  node_modules/ #dependencies for both the doc viewer builds and the dgeni stuff
                #This dir is .gitignored-ed
  gulpfile.js   #Tasks for generating docs and building & deploying the doc viewer
```

Closes #14361
This commit is contained in:
Pete Bacon Darwin
2017-02-09 19:58:36 +00:00
committed by Igor Minar
parent 5e7a2fa854
commit 600402d440
437 changed files with 855 additions and 531 deletions

View File

@ -0,0 +1,3 @@
module.exports = function exampleMap() {
return {};
};

View File

@ -0,0 +1,9 @@
module.exports = function getExampleFilename() {
function getExampleFilenameImpl(relativePath) {
return getExampleFilenameImpl.examplesFolder + relativePath;
}
getExampleFilenameImpl.examplesFolder = '@angular/examples/';
return getExampleFilenameImpl;
};

View File

@ -0,0 +1,55 @@
/**
* @dgService parseArgString
* @description
* processes an arg string in 'almost' the same fashion that the command processor does
* and returns an args object in yargs format.
* @kind function
* @param {String} str The arg string to process
* @return {Object} The args parsed into a yargs format.
*/
module.exports = function parseArgString() {
return function parseArgStringImpl(str) {
// regex from npm string-argv
//[^\s'"] Match if not a space ' or "
//+|['] or Match '
//([^']*) Match anything that is not '
//['] Close match if '
//+|["] or Match "
//([^"]*) Match anything that is not "
//["] Close match if "
var rx = /[^\s'"]+|[']([^']*?)[']|["]([^"]*?)["]/gi;
var value = str;
var unnammedArgs = [];
var args = {_: unnammedArgs};
var match, key;
do {
// Each call to exec returns the next regex match as an array
match = rx.exec(value);
if (match !== null) {
// Index 1 in the array is the captured group if it exists
// Index 0 is the matched text, which we use if no captured group exists
var arg = match[2] ? match[2] : (match[1] ? match[1] : match[0]);
if (key) {
args[key] = arg;
key = null;
} else {
if (arg.substr(arg.length - 1) === '=') {
key = arg.substr(0, arg.length - 1);
// remove leading '-' if it exists.
if (key.substr(0, 1) == '-') {
key = key.substr(1);
}
} else {
unnammedArgs.push(arg)
key = null;
}
}
}
} while (match !== null);
return args;
}
}

View File

@ -0,0 +1,7 @@
// These kind of comments are used CSS and other languages that do not support inline comments
module.exports = {
regionStartMatcher: /^\s*\/\*\s*#docregion\s*(.*)\s*\*\/\s*$/,
regionEndMatcher: /^\s*\/\*\s*#enddocregion\s*(.*)\s*\*\/\s*$/,
plasterMatcher: /^\s*\/\*\s*#docplaster\s*(.*)\s*\*\/\s*$/,
createPlasterComment: plaster => `/* ${plaster} */`
};

View File

@ -0,0 +1,55 @@
const matcher = require('./block-c');
describe('block-c region-matcher', () => {
it('should match start annotations', () => {
let matches;
matches = matcher.regionStartMatcher.exec('/* #docregion A b c */');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c ');
matches = matcher.regionStartMatcher.exec('/*#docregion A b c*/');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionStartMatcher.exec('/* #docregion */');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match end annotations', () => {
let matches;
matches = matcher.regionEndMatcher.exec('/* #enddocregion A b c */');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c ');
matches = matcher.regionEndMatcher.exec('/*#enddocregion A b c*/');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionEndMatcher.exec('/* #enddocregion */');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match plaster annotations', () => {
let matches;
matches = matcher.plasterMatcher.exec('/* #docplaster A b c */');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c ');
matches = matcher.plasterMatcher.exec('/*#docplaster A b c*/');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.plasterMatcher.exec('/* #docplaster */');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should create a plaster comment', () => {
expect(matcher.createPlasterComment('... elided ...')).toEqual('/* ... elided ... */');
});
});

View File

@ -0,0 +1,7 @@
// These kind of comments are used in HTML
module.exports = {
regionStartMatcher: /^\s*<!--\s*#docregion\s*(.*)\s*-->\s*$/,
regionEndMatcher: /^\s*<!--\s*#enddocregion\s*(.*)\s*-->\s*$/,
plasterMatcher: /^\s*<!--\s*#docplaster\s*(.*)\s*-->\s*$/,
createPlasterComment: plaster => `<!-- ${plaster} -->`
};

View File

@ -0,0 +1,55 @@
const matcher = require('./html');
describe('html region-matcher', () => {
it('should match start annotations', () => {
let matches;
matches = matcher.regionStartMatcher.exec('<!-- #docregion A b c -->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c ');
matches = matcher.regionStartMatcher.exec('<!--#docregion A b c-->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionStartMatcher.exec('<!-- #docregion -->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match end annotations', () => {
let matches;
matches = matcher.regionEndMatcher.exec('<!-- #enddocregion A b c -->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c ');
matches = matcher.regionEndMatcher.exec('<!--#enddocregion A b c-->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionEndMatcher.exec('<!-- #enddocregion -->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match plaster annotations', () => {
let matches;
matches = matcher.plasterMatcher.exec('<!-- #docplaster A b c -->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c ');
matches = matcher.plasterMatcher.exec('<!--#docplaster A b c-->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.plasterMatcher.exec('<!-- #docplaster -->');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should create a plaster comment', () => {
expect(matcher.createPlasterComment('... elided ...')).toEqual('<!-- ... elided ... -->');
});
});

View File

@ -0,0 +1,7 @@
// These kind of comments are used in languages that do not support block comments, such as Jade
module.exports = {
regionStartMatcher: /^\s*\/\/\s*#docregion\s*(.*)\s*$/,
regionEndMatcher: /^\s*\/\/\s*#enddocregion\s*(.*)\s*$/,
plasterMatcher: /^\s*\/\/\s*#docplaster\s*(.*)\s*$/,
createPlasterComment: plaster => `// ${plaster}`
};

View File

@ -0,0 +1,55 @@
const matcher = require('./inline-c-only');
describe('inline-c-only region-matcher', () => {
it('should match start annotations', () => {
let matches;
matches = matcher.regionStartMatcher.exec('// #docregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionStartMatcher.exec('//#docregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionStartMatcher.exec('// #docregion');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match end annotations', () => {
let matches;
matches = matcher.regionEndMatcher.exec('// #enddocregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionEndMatcher.exec('//#enddocregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionEndMatcher.exec('// #enddocregion');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match plaster annotations', () => {
let matches;
matches = matcher.plasterMatcher.exec('// #docplaster A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.plasterMatcher.exec('//#docplaster A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.plasterMatcher.exec('// #docplaster');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should create a plaster comment', () => {
expect(matcher.createPlasterComment('... elided ...')).toEqual('// ... elided ...');
});
});

View File

@ -0,0 +1,7 @@
// This comment type is used in C like languages such as JS, TS, Dart, etc
module.exports = {
regionStartMatcher: /^\s*\/\/\s*#docregion\s*(.*)\s*$/,
regionEndMatcher: /^\s*\/\/\s*#enddocregion\s*(.*)\s*$/,
plasterMatcher: /^\s*\/\/\s*#docplaster\s*(.*)\s*$/,
createPlasterComment: plaster => `/* ${plaster} */`
};

View File

@ -0,0 +1,55 @@
const matcher = require('./inline-c');
describe('inline-c region-matcher', () => {
it('should match start annotations', () => {
let matches;
matches = matcher.regionStartMatcher.exec('// #docregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionStartMatcher.exec('//#docregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionStartMatcher.exec('// #docregion');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match end annotations', () => {
let matches;
matches = matcher.regionEndMatcher.exec('// #enddocregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionEndMatcher.exec('//#enddocregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionEndMatcher.exec('// #enddocregion');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match plaster annotations', () => {
let matches;
matches = matcher.plasterMatcher.exec('// #docplaster A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.plasterMatcher.exec('//#docplaster A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.plasterMatcher.exec('// #docplaster');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should create a plaster comment', () => {
expect(matcher.createPlasterComment('... elided ...')).toEqual('/* ... elided ... */');
});
});

View File

@ -0,0 +1,7 @@
// These type of comments are used in hash comment based languages such as bash and Yaml
module.exports = {
regionStartMatcher: /^\s*#\s*#docregion\s*(.*)\s*$/,
regionEndMatcher: /^\s*#\s*#enddocregion\s*(.*)\s*$/,
plasterMatcher: /^\s*#\s*#docplaster\s*(.*)\s*$/,
createPlasterComment: plaster => `# ${plaster}`
};

View File

@ -0,0 +1,54 @@
const matcher = require('./inline-hash');
describe('inline-hash region-matcher', () => {
it('should match start annotations', () => {
let matches;
matches = matcher.regionStartMatcher.exec('# #docregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionStartMatcher.exec('##docregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionStartMatcher.exec('# #docregion');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match end annotations', () => {
let matches;
matches = matcher.regionEndMatcher.exec('# #enddocregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionEndMatcher.exec('##enddocregion A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.regionEndMatcher.exec('# #enddocregion');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should match plaster annotations', () => {
let matches;
matches = matcher.plasterMatcher.exec('# #docplaster A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.plasterMatcher.exec('##docplaster A b c');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('A b c');
matches = matcher.plasterMatcher.exec('# #docplaster');
expect(matches).not.toBeNull();
expect(matches[1]).toEqual('');
});
it('should create a plaster comment',
() => { expect(matcher.createPlasterComment('... elided ...')).toEqual('# ... elided ...'); });
});

View File

@ -0,0 +1,123 @@
const blockC = require('./region-matchers/block-c');
const html = require('./region-matchers/html');
const inlineC = require('./region-matchers/inline-c');
const inlineCOnly = require('./region-matchers/inline-c-only');
const inlineHash = require('./region-matchers/inline-hash');
const NO_NAME_REGION = '';
const DEFAULT_PLASTER = '. . .';
const {mapObject} = require('../utils');
module.exports = function regionParser() {
return regionParserImpl;
};
regionParserImpl.regionMatchers = {
ts: inlineC,
js: inlineC,
es6: inlineC,
dart: inlineC,
html: html,
css: blockC,
yaml: inlineHash,
jade: inlineCOnly
};
/**
* @param contents string
* @param fileType string
* @returns {contents: string, regions: {[regionName: string]: string}}
*/
function regionParserImpl(contents, fileType) {
const regionMatcher = regionParserImpl.regionMatchers[fileType];
const openRegions = [];
const regionMap = {};
if (regionMatcher) {
let plaster = regionMatcher.createPlasterComment(DEFAULT_PLASTER);
const lines = contents.split(/\r?\n/).filter((line, index) => {
const startRegion = line.match(regionMatcher.regionStartMatcher);
const endRegion = line.match(regionMatcher.regionEndMatcher);
const updatePlaster = line.match(regionMatcher.plasterMatcher);
// start region processing
if (startRegion) {
// open up the specified region
const regionNames = getRegionNames(startRegion[1]);
if (regionNames.length === 0) {
regionNames.push('');
}
regionNames.forEach(regionName => {
const region = regionMap[regionName];
if (region) {
if (region.open) {
throw new RegionParserError(
`Tried to open a region, named "${regionName}", that is already open`, index);
}
region.open = true;
region.lines.push(plaster);
} else {
regionMap[regionName] = {lines: [], open: true};
}
openRegions.push(regionName);
});
// end region processing
} else if (endRegion) {
if (openRegions.length === 0) {
throw new RegionParserError('Tried to close a region when none are open', index);
}
// close down the specified region (or most recent if no name is given)
const regionNames = getRegionNames(endRegion[1]);
if (regionNames.length === 0) {
regionNames.push(openRegions[openRegions.length - 1]);
}
regionNames.forEach(regionName => {
const region = regionMap[regionName];
if (!region || !region.open) {
throw new RegionParserError(
`Tried to close a region, named "${regionName}", that is not open`, index);
}
region.open = false;
removeLast(openRegions, regionName);
});
// doc plaster processing
} else if (updatePlaster) {
plaster = regionMatcher.createPlasterComment(updatePlaster[1].trim());
// simple line of content processing
} else {
openRegions.forEach(regionName => regionMap[regionName].lines.push(line));
// do not filter out this line from the content
return true;
}
// this line contained an annotation so let's filter it out
return false;
});
return {
contents: lines.join('\n'),
regions: mapObject(regionMap, (regionName, region) => region.lines.join('\n'))
};
} else {
return {contents, regions: {}};
}
}
function getRegionNames(input) {
return input.split(',').map(name => name.trim()).filter(name => name.length > 0);
}
function removeLast(array, item) {
const index = array.lastIndexOf(item);
array.splice(index, 1);
}
function RegionParserError(message, lineNum) {
this.message = `regionParser: ${message} (at line ${lineNum}).`;
this.lineNum = lineNum;
this.stack = (new Error()).stack;
}
RegionParserError.prototype = Object.create(Error.prototype);
RegionParserError.prototype.constructor = RegionParserError;

View File

@ -0,0 +1,158 @@
var testPackage = require('../../helpers/test-package');
var Dgeni = require('dgeni');
const testRegionMatcher = {
regionStartMatcher: /^\s*\/\*\s*#docregion\s+(.*)\s*\*\/\s*$/,
regionEndMatcher: /^\s*\/\*\s*#enddocregion\s+(.*)\s*\*\/\s*$/,
plasterMatcher: /^\s*\/\*\s*#docplaster\s+(.*)\s*\*\/\s*$/,
createPlasterComment: plaster => `/* ${plaster} */`
};
describe('regionParser service', () => {
var dgeni, injector, regionParser;
beforeEach(function() {
dgeni = new Dgeni([testPackage('examples-package', true)]);
injector = dgeni.configureInjector();
regionParser = injector.get('regionParser');
regionParser.regionMatchers = {'test-type': testRegionMatcher};
});
it('should return just the contents if there is no region-matcher for the file type', () => {
const output = regionParser('some contents', 'unknown');
expect(output).toEqual({contents: 'some contents', regions: {}});
});
it('should return just the contents if there is a region-matcher but no regions', () => {
const output = regionParser('some contents', 'test-type');
expect(output).toEqual({contents: 'some contents', regions: {}});
});
it('should remove start region annotations from the contents', () => {
const output = regionParser(
t('/* #docregion */', 'abc', '/* #docregion X */', 'def', '/* #docregion Y */', 'ghi'),
'test-type');
expect(output.contents).toEqual(t('abc', 'def', 'ghi'));
});
it('should remove end region annotations from the contents', () => {
const output = regionParser(
t('/* #docregion */', 'abc', '/* #docregion X */', 'def', '/* #enddocregion X */',
'/* #docregion Y */', 'ghi', '/* #enddocregion Y */', '/* #enddocregion */'),
'test-type');
expect(output.contents).toEqual(t('abc', 'def', 'ghi'));
});
it('should remove doc plaster annotations from the contents', () => {
const output =
regionParser(t('/* #docplaster ... elided ... */', 'abc', 'def', 'ghi'), 'test-type');
expect(output.contents).toEqual(t('abc', 'def', 'ghi'));
});
it('should capture the rest of the contents for a region with no end region annotation', () => {
const output = regionParser(
t('/* #docregion */', 'abc', '/* #docregion X */', 'def', '/* #docregion Y */', 'ghi'),
'test-type');
expect(output.regions['']).toEqual(t('abc', 'def', 'ghi'));
expect(output.regions['X']).toEqual(t('def', 'ghi'));
expect(output.regions['Y']).toEqual(t('ghi'));
});
it('should capture the contents for a region up to the end region annotation', () => {
const output = regionParser(
t('/* #docregion */', 'abc', '/* #enddocregion */', '/* #docregion X */', 'def',
'/* #enddocregion X */', '/* #docregion Y */', 'ghi', '/* #enddocregion Y */'),
'test-type');
expect(output.regions['']).toEqual(t('abc'));
expect(output.regions['X']).toEqual(t('def'));
expect(output.regions['Y']).toEqual(t('ghi'));
});
it('should open a region with a null name if there is no region name', () => {
const output = regionParser(t('/* #docregion */', 'abc', '/* #enddocregion */'), 'test-type');
expect(output.regions['']).toEqual('abc');
});
it('should close the most recently opened region if there is no region name', () => {
const output = regionParser(
t('/* #docregion X*/', 'abc', '/* #docregion Y */', 'def', '/* #enddocregion */', 'ghi',
'/* #enddocregion */'),
'test-type');
expect(output.regions['X']).toEqual(t('abc', 'def', 'ghi'));
expect(output.regions['Y']).toEqual(t('def'));
});
it('should handle overlapping regions', () => {
const output = regionParser(
t('/* #docregion X*/', 'abc', '/* #docregion Y */', 'def', '/* #enddocregion X */', 'ghi',
'/* #enddocregion Y */'),
'test-type');
expect(output.regions['X']).toEqual(t('abc', 'def'));
expect(output.regions['Y']).toEqual(t('def', 'ghi'));
});
it('should error if we attempt to open an already open region', () => {
expect(() => regionParser(t('/* #docregion */', 'abc', '/* #docregion */', 'def'), 'test-type'))
.toThrowError(
'regionParser: Tried to open a region, named "", that is already open (at line 2).');
expect(
() =>
regionParser(t('/* #docregion X */', 'abc', '/* #docregion X */', 'def'), 'test-type'))
.toThrowError(
'regionParser: Tried to open a region, named "X", that is already open (at line 2).');
});
it('should error if we attempt to close an already closed region', () => {
expect(() => regionParser(t('abc', '/* #enddocregion */', 'def'), 'test-type'))
.toThrowError('regionParser: Tried to close a region when none are open (at line 1).');
expect(
() =>
regionParser(t('/* #docregion */', 'abc', '/* #enddocregion X */', 'def'), 'test-type'))
.toThrowError(
'regionParser: Tried to close a region, named "X", that is not open (at line 2).');
});
it('should handle whitespace in region names on single annotation', () => {
const output =
regionParser(t('/* #docregion A B*/', 'abc', '/* #docregion A C */', 'def'), 'test-type');
expect(output.regions['A B']).toEqual(t('abc', 'def'));
expect(output.regions['A C']).toEqual(t('def'));
});
it('should join multiple regions with the default plaster string (". . .")', () => {
const output = regionParser(
t('/* #docregion */', 'abc', '/* #enddocregion */', 'def', '/* #docregion */', 'ghi',
'/* #enddocregion */'),
'test-type');
expect(output.regions['']).toEqual(t('abc', '/* . . . */', 'ghi'));
});
it('should join multiple regions with the current plaster string', () => {
const output = regionParser(
t('/* #docregion */', 'abc', '/* #enddocregion */', 'def', '/* #docregion */', 'ghi',
'/* #enddocregion */', '/* #docplaster ... elided ... */', '/* #docregion A */', 'jkl',
'/* #enddocregion A */', 'mno', '/* #docregion A */', 'pqr', '/* #enddocregion A */'),
'test-type');
expect(output.regions['']).toEqual(t('abc', '/* . . . */', 'ghi'));
expect(output.regions['A']).toEqual(t('jkl', '/* ... elided ... */', 'pqr'));
});
it('should parse multiple region names separated by commas', () => {
const output = regionParser(
t('/* #docregion , A, B */', 'abc', '/* #enddocregion B */', '/* #docregion C */', 'xyz',
'/* #enddocregion A, C, */'),
'test-type');
expect(output.regions['A']).toEqual(t('abc', 'xyz'));
expect(output.regions['B']).toEqual(t('abc'));
expect(output.regions['C']).toEqual(t('xyz'));
})
});
function t() {
return Array.prototype.join.call(arguments, '\n');
}