chore: fix "Invalid example" warnings from shred map builder

closes #1832
The shred map (xref) builder was issuing warnings. This fix includes
- Adjustments to the shredder map builder itself so that it
understands, e.g., app-project relative example paths.
- `**/guide/glossary.jade` now (Jade) `includes` the shared parent
`glossary.jade` rather than (Harp) importing (via `partial`). This
fixes `makeExample` path issues in the glossary.
- Adjusted some `makeExample` paths that were ok for site build, but
confused the xref tool.
This commit is contained in:
Patrice Chalin 2016-07-05 16:46:44 -07:00 committed by Ward Bell
parent 0664a271ba
commit fb9edf972e
6 changed files with 51 additions and 31 deletions

View File

@ -101,7 +101,7 @@ block dart-map-alternative
As an alternative to using a configuration `Map`, we can define As an alternative to using a configuration `Map`, we can define
a custom configuration class: a custom configuration class:
+makeExample('dependency-injection/ts/app/app.config.ts','config-alt','app/app-config.ts (alternative config)')(format='.') +makeExample('lib/app_config.dart (alternative config)','config-alt')
:marked :marked
Defining a configuration class has a few benefits. One key benefit Defining a configuration class has a few benefits. One key benefit

View File

@ -1 +1 @@
!= partial("../glossary") include ../glossary

View File

@ -132,9 +132,6 @@ code-example(language="bash").
### Add a base tag ### Add a base tag
// Our Tour of Heroes needs routing,
// so we load the library in the `index.html` in a script tag immediately *after* the angular script itself.
//+makeExample('toh-5/dart/web/index.html', 'router', 'index.html (router)')(format=".")
:marked :marked
First, edit `index.html` and add `<base href="/">` at the top of the `<head>` section. First, edit `index.html` and add `<base href="/">` at the top of the `<head>` section.
+makeExample('toh-5/dart/web/index.html', 'base-href', 'index.html (base href)')(format=".") +makeExample('toh-5/dart/web/index.html', 'base-href', 'index.html (base href)')(format=".")

View File

@ -54,7 +54,7 @@ include _util-fns
The barrel itself is a module file that re-exports *selected* exports of other modules. The barrel itself is a module file that re-exports *selected* exports of other modules.
Imagine three modules in a `heroes` folder: Imagine three modules in a `heroes` folder:
code-example(format=''). code-example.
// heroes/hero.component.ts // heroes/hero.component.ts
export class HeroComponent {} export class HeroComponent {}
@ -65,26 +65,26 @@ include _util-fns
export class HeroService {} export class HeroService {}
:marked :marked
Without a barrel, a consumer would need three import statements: Without a barrel, a consumer would need three import statements:
code-example(format=''). code-example.
import { HeroComponent } from '../heroes/hero.component.ts'; import { HeroComponent } from '../heroes/hero.component.ts';
import { Hero } from '../heroes/hero.model.ts'; import { Hero } from '../heroes/hero.model.ts';
import { HeroService } from '../heroes/hero.service.ts'; import { HeroService } from '../heroes/hero.service.ts';
:marked :marked
We can add a barrel to the `heroes` folder (called `index` by convention) that exports all of these items: We can add a barrel to the `heroes` folder (called `index` by convention) that exports all of these items:
code-example(format=''). code-example.
export * from './hero.model.ts'; // re-export all of its exports export * from './hero.model.ts'; // re-export all of its exports
export * from './hero.service.ts'; // re-export all of its exports export * from './hero.service.ts'; // re-export all of its exports
export { HeroComponent } from './hero.component.ts'; // re-export the named thing export { HeroComponent } from './hero.component.ts'; // re-export the named thing
:marked :marked
Now a consumer can import what it needs from the barrel. Now a consumer can import what it needs from the barrel.
code-example(format=''). code-example.
import { Hero, HeroService } from '../heroes'; // index is implied import { Hero, HeroService } from '../heroes'; // index is implied
:marked :marked
The Angular [scoped packages](#scoped-package) each have a barrel named `index`. The Angular [scoped packages](#scoped-package) each have a barrel named `index`.
// #enddocregion b-c // #enddocregion b-c
:marked :marked
That's why we can write this: That's why we can write this:
+makeExample('../docs/_fragments/quickstart/ts/app/app.component.ts', 'import')(format=".") +makeExcerpt('quickstart/ts/app/app.component.ts', 'import', '')
// #docregion b-c // #docregion b-c
:marked :marked
@ -584,7 +584,7 @@ include _util-fns
The only difference, from a consumer perspective, The only difference, from a consumer perspective,
is that the package name begins with the Angular *scope name*, `@angular`. is that the package name begins with the Angular *scope name*, `@angular`.
+makeExample('../docs/_fragments/architecture/ts/app/app.component.ts', 'import')(format=".") +makeExcerpt('architecture/ts/app/app.component.ts', 'import', '')
// #docregion n-s-2 // #docregion n-s-2
:marked :marked

View File

@ -1 +1 @@
!= partial("../glossary") include ../glossary

View File

@ -18,25 +18,37 @@ module.exports = function shredMapProcessor(log, createDocMessage) {
var fragToJadeMap = {}; var fragToJadeMap = {};
docs.forEach(function(doc) { docs.forEach(function(doc) {
var jadePath = path.join(options.jadeDir, doc.fileInfo.relativePath); var relativePath = doc.fileInfo.relativePath;
var jadePath = path.join(options.jadeDir, relativePath);
var lang = relativePath.substr(0, relativePath.indexOf('\/'));
var appProjDirName = jadeBaseFileNameToExampleName(doc.fileInfo.baseName);
var fragInfoSet = {}; var fragInfoSet = {};
doc.fragItems.forEach(function(fragItem) { doc.fragItems.forEach(function(fragItem) {
var mixinPath = fragItem.mixinPath; var mixinPath = fragItem.mixinPath;
var fullExamplePath; var fullExamplePath;
// Normalize mixinPath: strip out optional trailing '(...)'
var mixinPath = mixinPath.replace(/ \([^\)]*\)/,'');
if ( mixinPath.indexOf('_api') >= 0) { if ( mixinPath.indexOf('_api') >= 0) {
var sourcePath = mixinPath.replace('_api/',''); var sourcePath = mixinPath.replace('_api/','');
fullExamplePath = path.join(options.apiExamplesDir, sourcePath); fullExamplePath = path.join(options.apiExamplesDir, sourcePath);
} else { } else {
fullExamplePath = path.join(options.devguideExamplesDir, mixinPath); fullExamplePath = path.join(options.devguideExamplesDir, mixinPath);
} }
var region = fragItem.region ? "-" + fragItem.region : ''; var fragInfo = makeFragInfo(options.fragmentsDir, fullExamplePath, fragItem, mixinPath);
var extn = path.extname(mixinPath); if (!fragInfo.exists) {
var basename = path.basename(mixinPath, extn); var savedFragInfo = fragInfo;
var fragDir = path.dirname(mixinPath); // Assume that mixinPath is actually app-project-folder relative and
var fragPath = path.join(fragDir, basename + region + extn) + '.md'; // prepend "lang/appProjDirName":
var fullFragPath = path.join(options.fragmentsDir, fragPath); var appProjRelPath = mixinPath;
mixinPath = appProjDirName + '/' + lang + '/' + mixinPath;
var fragInfo = { fragPath: fullFragPath, examplePath: fullExamplePath, exists: fs.existsSync(fullFragPath) }; fragInfo = makeFragInfo(options.fragmentsDir, fullExamplePath, fragItem, mixinPath);
if (fragInfo.exists) {
log.info('Ajusted example path (' + doc.fileInfo.baseName + '): ' + appProjRelPath + ' -> ' + mixinPath);
} else {
fragInfo = savedFragInfo;
}
}
var fragPath = fragInfo.relFragPath;
fragInfoSet[fragPath] = fragInfo; fragInfoSet[fragPath] = fragInfo;
if (fragInfo.exists) { if (fragInfo.exists) {
var jadePathsSet = fragToJadeMap[fragPath]; var jadePathsSet = fragToJadeMap[fragPath];
@ -46,7 +58,7 @@ module.exports = function shredMapProcessor(log, createDocMessage) {
} }
jadePathsSet[jadePath] = jadePath; jadePathsSet[jadePath] = jadePath;
} else { } else {
var relativePath = path.relative(".", fullFragPath); var relativePath = path.relative(".", fragInfo.fragPath);
log.warn(createDocMessage('Invalid example (unable to locate fragment file: "' + relativePath + '")', doc)); log.warn(createDocMessage('Invalid example (unable to locate fragment file: "' + relativePath + '")', doc));
} }
}); });
@ -82,13 +94,24 @@ module.exports = function shredMapProcessor(log, createDocMessage) {
} }
}; };
function getExampleName(fragPath) { // TODO: use the functionality in public/resources/js/util.js once it lands.
// pattern to isolate base fileName and extension from fragment name function jadeBaseFileNameToExampleName(name) {
var rx = /(.*)\-(.*)\.(.s)/; // Adjust for known cases where chapter name is not the example name.
var r = rx.exec(fragPath); var matches = name.match(/(toh-)pt(\d+)/);
if (r) { if (matches) name = matches[1] + matches[2];
return r[1] + '.' + r[3]; return name;
} else { }
return fragPath;
} function makeFragInfo(fragmentsDir, fullExamplePath, fragItem, mixinPath) {
var region = fragItem.region ? "-" + fragItem.region : '';
var extn = path.extname(mixinPath);
var basename = path.basename(mixinPath, extn);
var fragDir = path.dirname(mixinPath);
var fragPath = path.join(fragDir, basename + region + extn) + '.md';
var fullFragPath = path.join(fragmentsDir, fragPath);
return {
fragPath: fullFragPath,
relFragPath: fragPath,
examplePath: fullExamplePath,
exists: fs.existsSync(fullFragPath) };
} }