diff --git a/aio/src/app/documents/document.service.spec.ts b/aio/src/app/documents/document.service.spec.ts
index 4acddefe7c..8b083e391b 100644
--- a/aio/src/app/documents/document.service.spec.ts
+++ b/aio/src/app/documents/document.service.spec.ts
@@ -67,29 +67,17 @@ describe('DocumentService', () => {
expect(latestDocument).toEqual(doc1);
});
- // HACK: PREPARE FOR CHANGING TO CASE-INSENSITIVE URLS
- it('should attempt disambiguated document paths if the document is not found on the server', () => {
- let currentDocument: DocumentContents|undefined;
- const notFoundDoc = { id: FILE_NOT_FOUND_ID, contents: '
Page Not Found
' };
- const { docService, logger } = getServices('missing/Doc-1');
- docService.currentDocument.subscribe(doc => currentDocument = doc);
-
- // Initial request return 404.
- httpMock.expectOne({url: 'generated/docs/missing/Doc-1.json'}).flush(null, {status: 404, statusText: 'NOT FOUND'});
- httpMock.expectOne({url: 'generated/docs/missing/d_oc-1.json'}).flush(null, {status: 404, statusText: 'NOT FOUND'});
- httpMock.expectOne({url: 'generated/docs/missing/d_oc.json'}).flush(null, {status: 404, statusText: 'NOT FOUND'});
- expect(logger.output.error).toEqual([
- [jasmine.any(Error)]
- ]);
- expect(logger.output.error[0][0].message).toEqual(`Document file not found at 'missing/Doc-1'`);
-
- // Subsequent request for not-found document.
- logger.output.error = [];
- httpMock.expectOne(CONTENT_URL_PREFIX + 'file-not-found.json').flush(notFoundDoc);
- expect(logger.output.error).toEqual([]); // does not report repeated errors
- expect(currentDocument).toEqual(notFoundDoc);
+ it('should encode the request path to be case-insensitive', () => {
+ const { docService, locationService } = getServices('initial/Doc');
+ docService.currentDocument.subscribe();
+ httpMock.expectOne(CONTENT_URL_PREFIX + 'initial/d_oc.json').flush({});
+ locationService.go('NEW/Doc');
+ httpMock.expectOne(CONTENT_URL_PREFIX + 'n_e_w_/d_oc.json').flush({});
+ locationService.go('doc_with_underscores');
+ httpMock.expectOne(CONTENT_URL_PREFIX + 'doc__with__underscores.json').flush({});
+ locationService.go('DOC_WITH_UNDERSCORES');
+ httpMock.expectOne(CONTENT_URL_PREFIX + 'd_o_c___w_i_t_h___u_n_d_e_r_s_c_o_r_e_s_.json').flush({});
});
- // END HACK: PREPARE FOR CHANGING TO CASE-INSENSITIVE URLS
it('should emit the not-found document if the document is not found on the server', () => {
let currentDocument: DocumentContents|undefined;
@@ -119,7 +107,7 @@ describe('DocumentService', () => {
docService.currentDocument.subscribe(doc => currentDocument = doc);
- httpMock.expectOne({}).flush(null, { status: 404, statusText: 'NOT FOUND'});
+ httpMock.expectOne({}).flush(null, {status: 404, statusText: 'NOT FOUND'});
expect(currentDocument).toEqual(hardCodedNotFoundDoc);
// now check that we haven't killed the currentDocument observable sequence
@@ -143,7 +131,7 @@ describe('DocumentService', () => {
[jasmine.any(Error)]
]);
expect(logger.output.error[0][0].message)
- .toEqual(`Error fetching document 'initial/doc': (Http failure response for generated/docs/initial/doc.json: 500 Server Error)`);
+ .toEqual(`Error fetching document 'initial/doc': (Http failure response for generated/docs/initial/doc.json: 500 Server Error)`);
locationService.go('new/doc');
httpMock.expectOne({}).flush(doc1);
diff --git a/aio/src/app/documents/document.service.ts b/aio/src/app/documents/document.service.ts
index 9d521f3232..73ab9a0ec3 100644
--- a/aio/src/app/documents/document.service.ts
+++ b/aio/src/app/documents/document.service.ts
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
-import { AsyncSubject, Observable, of, throwError } from 'rxjs';
+import { AsyncSubject, Observable, of } from 'rxjs';
import { catchError, switchMap, tap } from 'rxjs/operators';
import { DocumentContents } from './document-contents';
@@ -53,7 +53,7 @@ export class DocumentService {
}
private fetchDocument(id: string): Observable {
- const requestPath = `${DOC_CONTENT_URL_PREFIX}${id}.json`;
+ const requestPath = `${DOC_CONTENT_URL_PREFIX}${encodeToLowercase(id)}.json`;
const subject = new AsyncSubject();
this.logger.log('fetching document from', requestPath);
@@ -66,20 +66,6 @@ export class DocumentService {
throw Error('Invalid data');
}
}),
- // HACK: PREPARE FOR CHANGING TO CASE-INSENSITIVE URLS
- catchError((error: HttpErrorResponse) => {
- const encodedPath = encodeToLowercase(requestPath);
- return error.status === 404 && encodedPath !== requestPath ?
- this.http.get(encodedPath) :
- throwError(error);
- }),
- catchError((error: HttpErrorResponse) => {
- const disambiguatedPath = convertDisambiguatedPath(requestPath);
- return error.status === 404 && disambiguatedPath !== requestPath ?
- this.http.get(disambiguatedPath) :
- throwError(error);
- }),
- // END HACK: PREPARE FOR CHANGING TO CASE-INSENSITIVE URLS
catchError((error: HttpErrorResponse) => {
return error.status === 404 ? this.getFileNotFoundDoc(id) : this.getErrorDoc(id, error);
}),
@@ -123,18 +109,3 @@ export class DocumentService {
function encodeToLowercase(str: string): string {
return str.replace(/[A-Z_]/g, char => char.toLowerCase() + '_');
}
-
-/**
- * A temporary function to deal with a future change to URL disambiguation.
- *
- * Currently there are disambiguated URLs such as `INJECTOR-0` and `Injector-1`, which
- * will attempt to load their document contents from `injector-0.json` and `injector-1.json`
- * respectively. In a future version of the AIO app, the disambiguation will be changed to
- * escape the upper-case characters instead.
- *
- * This function will be called if the current AIO is trying to request documents from a
- * server that has been updated to use the new disambiguated URLs.
- */
-function convertDisambiguatedPath(str: string): string {
- return encodeToLowercase(str.replace(/-\d+\.json$/, '.json'));
-}
diff --git a/aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts b/aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts
index 14dced3048..2d58484fc6 100644
--- a/aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts
+++ b/aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts
@@ -62,7 +62,7 @@ describe(browser.baseUrl, () => {
describe('(api docs pages)', () => {
const textPerUrl: { [key: string]: string } = {
- /* Class */ 'api/core/Injector-0': 'class injector',
+ /* Class */ 'api/core/Injector': 'class injector',
/* Const */ 'api/forms/NG_VALIDATORS': 'const ng_validators',
/* Decorator */ 'api/core/Component': '@component',
/* Directive */ 'api/common/NgIf': 'class ngif',
diff --git a/aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.js b/aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.js
index 0a070a26be..5c0f4a595d 100644
--- a/aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.js
+++ b/aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.js
@@ -2,7 +2,7 @@
* @dgProcessor disambiguateDocPathsProcessor
* @description
*
- * Ensures that docs that have the same path, other than case changes,
+ * Ensures that docs that have the same output path, other than case changes,
* are disambiguated.
*
* For example in Angular there is the `ROUTES` const and a `Routes` type.
@@ -14,55 +14,30 @@
* ```
*
* but in a case-insensitive file-system these two paths point to the same file!
+ *
+ * So this processor will encode the paths into lower case that is not affected
+ * by case-insensitive file-systems.
*/
-module.exports = function disambiguateDocPathsProcessor(log) {
+module.exports = function disambiguateDocPathsProcessor() {
return {
$runAfter: ['paths-computed'],
$runBefore: ['rendering-docs', 'createSitemap'],
$process(docs) {
- // Collect all the ambiguous docs, whose outputPath is are only different by casing.
- const ambiguousDocMap = new Map();
for (const doc of docs) {
if (!doc.outputPath) {
continue;
}
- const outputPath = doc.outputPath.toLowerCase();
- if (!ambiguousDocMap.has(outputPath)) {
- ambiguousDocMap.set(outputPath, []);
- }
- const ambiguousDocs = ambiguousDocMap.get(outputPath);
- ambiguousDocs.push(doc);
- }
-
- // Create a disambiguator doc for each set of such ambiguous docs,
- // and update the ambiguous docs to have unique `path` and `outputPath` properties.
- for (const [outputPath, ambiguousDocs] of ambiguousDocMap) {
- if (ambiguousDocs.length === 1) {
- continue;
- }
-
- log.debug('Docs with ambiguous outputPath:' + ambiguousDocs.map((d, i) => `\n - ${d.id}: "${d.outputPath}" replaced with "${convertPath(d.outputPath, i)}".`));
-
- const doc = ambiguousDocs[0];
- const path = doc.path;
- const id = `${doc.id.toLowerCase()}-disambiguator`;
- const title = `${doc.id.toLowerCase()} (disambiguation)`;
- const aliases = [id];
- docs.push({ docType: 'disambiguator', id, title, aliases, path, outputPath, docs: ambiguousDocs });
-
- // Update the paths
- let count = 0;
- for (const doc of ambiguousDocs) {
- doc.path = convertPath(doc.path, count);
- doc.outputPath = convertPath(doc.outputPath, count);
- count += 1;
- }
+ doc.outputPath = encodeToLowercase(doc.outputPath);
}
}
};
};
-function convertPath(path, count) {
- // Add the counter before any extension
- return path.replace(/(\.[^.]*)?$/, `-${count}$1`);
+/**
+ * To avoid collisions on case-insensitive file-systems, we encode the path to the content in
+ * a deterministic case-insensitive form - converting all uppercase letters to lowercase followed
+ * by an underscore.
+ */
+function encodeToLowercase(str) {
+ return str.replace(/[A-Z_]/g, char => char.toLowerCase() + '_');
}
diff --git a/aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.spec.js b/aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.spec.js
index 22eae728c1..45691df274 100644
--- a/aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.spec.js
+++ b/aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.spec.js
@@ -9,12 +9,14 @@ describe('disambiguateDocPaths processor', () => {
injector = dgeni.configureInjector();
processor = injector.get('disambiguateDocPathsProcessor');
docs = [
- {docType: 'test-doc', id: 'test-doc', path: 'test/doc', outputPath: 'test/doc.json'},
- {docType: 'test-doc', id: 'TEST-DOC', path: 'TEST/DOC', outputPath: 'TEST/DOC.json'},
- {docType: 'test-doc', id: 'test-Doc', path: 'test/Doc', outputPath: 'test/Doc.xml'},
- {docType: 'test-doc', id: 'unique-doc', path: 'unique/doc', outputPath: 'unique/doc.json'},
- {docType: 'test-doc', id: 'other-doc', path: 'other/doc', outputPath: 'other/doc.json'},
- {docType: 'test-doc', id: 'other-DOC', path: 'other/DOC', outputPath: 'other/DOC.json'},
+ { docType: 'test-doc', id: 'test-doc', path: 'test/doc', outputPath: 'test/doc.json' },
+ { docType: 'test-doc', id: 'TEST-DOC', path: 'TEST/DOC', outputPath: 'TEST/DOC.json' },
+ { docType: 'test-doc', id: 'test-Doc', path: 'test/Doc', outputPath: 'test/Doc.xml' },
+ { docType: 'test-doc', id: 'unique-doc', path: 'unique/doc', outputPath: 'unique/doc.json' },
+ { docType: 'test-doc', id: 'other-doc', path: 'other/doc', outputPath: 'other/doc.json' },
+ { docType: 'test-doc', id: 'other-DOC', path: 'other/DOC', outputPath: 'other/DOC.json' },
+ { docType: 'test-doc', id: 'has_underscore', path: 'has_underscore', outputPath: 'has_underscore.json' },
+ { docType: 'test-doc', id: 'HAS_UNDERSCORE', path: 'HAS_UNDERSCORE', outputPath: 'HAS_UNDERSCORE.json' },
];
});
@@ -26,44 +28,23 @@ describe('disambiguateDocPaths processor', () => {
expect(processor.$runBefore).toContain('createSitemap');
});
- it('should create `disambiguator` documents for docs that have ambiguous outputPaths', () => {
- const numDocs = docs.length;
+ it('should update the path and outputPath properties of each doc to be unambiguous on case-insensitive file-systems', () => {
processor.$process(docs);
- expect(docs.length).toEqual(numDocs + 2);
- expect(docs[docs.length - 2]).toEqual({
- docType: 'disambiguator',
- id: 'test-doc-disambiguator',
- title: 'test-doc (disambiguation)',
- aliases: ['test-doc-disambiguator'],
- path: 'test/doc',
- outputPath: 'test/doc.json',
- docs: [docs[0], docs[1]],
- });
- expect(docs[docs.length - 1]).toEqual({
- docType: 'disambiguator',
- id: 'other-doc-disambiguator',
- title: 'other-doc (disambiguation)',
- aliases: ['other-doc-disambiguator'],
- path: 'other/doc',
- outputPath: 'other/doc.json',
- docs: [docs[4], docs[5]],
- });
- });
-
- it('should update the path and outputPath properties of each ambiguous doc', () => {
- processor.$process(docs);
- expect(docs[0].path).toEqual('test/doc-0');
- expect(docs[0].outputPath).toEqual('test/doc-0.json');
- expect(docs[1].path).toEqual('TEST/DOC-1');
- expect(docs[1].outputPath).toEqual('TEST/DOC-1.json');
-
- // The non-ambiguous docs are left alone
- expect(docs[2].outputPath).toEqual('test/Doc.xml');
+ expect(docs[0].path).toEqual('test/doc');
+ expect(docs[0].outputPath).toEqual('test/doc.json');
+ expect(docs[1].path).toEqual('TEST/DOC');
+ expect(docs[1].outputPath).toEqual('t_e_s_t_/d_o_c_.json');
+ expect(docs[2].path).toEqual('test/Doc');
+ expect(docs[2].outputPath).toEqual('test/d_oc.xml');
+ expect(docs[3].path).toEqual('unique/doc');
expect(docs[3].outputPath).toEqual('unique/doc.json');
-
- expect(docs[4].path).toEqual('other/doc-0');
- expect(docs[4].outputPath).toEqual('other/doc-0.json');
- expect(docs[5].path).toEqual('other/DOC-1');
- expect(docs[5].outputPath).toEqual('other/DOC-1.json');
+ expect(docs[4].path).toEqual('other/doc');
+ expect(docs[4].outputPath).toEqual('other/doc.json');
+ expect(docs[5].path).toEqual('other/DOC');
+ expect(docs[5].outputPath).toEqual('other/d_o_c_.json');
+ expect(docs[6].path).toEqual('has_underscore');
+ expect(docs[6].outputPath).toEqual('has__underscore.json');
+ expect(docs[7].path).toEqual('HAS_UNDERSCORE');
+ expect(docs[7].outputPath).toEqual('h_a_s___u_n_d_e_r_s_c_o_r_e_.json');
});
});
diff --git a/aio/tools/transforms/authors-package/index.spec.js b/aio/tools/transforms/authors-package/index.spec.js
index 440bc400c1..525ea7a702 100644
--- a/aio/tools/transforms/authors-package/index.spec.js
+++ b/aio/tools/transforms/authors-package/index.spec.js
@@ -71,14 +71,14 @@ describe('authors-package (integration tests)', () => {
it('should generate API doc if the "fileChanged" is an API doc', () => {
return generateDocs('packages/forms/src/form_builder.ts', { silent: true }).then(() => {
expect(fs.writeFile).toHaveBeenCalled();
- expect(files).toContain(resolve(DOCS_OUTPUT_PATH, 'api/forms/FormBuilder.json'));
+ expect(files).toContain(resolve(DOCS_OUTPUT_PATH, 'api/forms/f_ormb_uilder.json'));
});
}, 16000);
it('should generate API doc if the "fileChanged" is an API example', () => {
return generateDocs('packages/examples/forms/ts/formBuilder/form_builder_example.ts', { silent: true }).then(() => {
expect(fs.writeFile).toHaveBeenCalled();
- expect(files).toContain(resolve(DOCS_OUTPUT_PATH, 'api/forms/FormBuilder.json'));
+ expect(files).toContain(resolve(DOCS_OUTPUT_PATH, 'api/forms/f_ormb_uilder.json'));
});
}, 16000);
});
diff --git a/goldens/size-tracking/aio-payloads.json b/goldens/size-tracking/aio-payloads.json
index 4dd3b70d74..53b1d231a8 100755
--- a/goldens/size-tracking/aio-payloads.json
+++ b/goldens/size-tracking/aio-payloads.json
@@ -3,7 +3,7 @@
"master": {
"uncompressed": {
"runtime-es2017": 4619,
- "main-es2017": 456795,
+ "main-es2017": 456578,
"polyfills-es2017": 55210
}
}