build(aio): add tests for Firebase redirection (#21712)
PR Close #21712
This commit is contained in:
parent
43d1b9864f
commit
01cef016ee
|
@ -43,6 +43,7 @@
|
|||
"docs-watch": "node tools/transforms/authors-package/watchr.js",
|
||||
"docs-lint": "eslint --ignore-path=\"tools/transforms/.eslintignore\" tools/transforms",
|
||||
"docs-test": "node tools/transforms/test.js",
|
||||
"redirects-test": "jasmine-ts tools/firebase-test-utils/*.spec.ts",
|
||||
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js",
|
||||
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch\" \"yarn start\"",
|
||||
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
|
||||
|
@ -96,6 +97,7 @@
|
|||
"archiver": "^1.3.0",
|
||||
"canonical-path": "^0.0.2",
|
||||
"chalk": "^2.1.0",
|
||||
"cjson": "^0.5.0",
|
||||
"codelyzer": "~2.0.0",
|
||||
"concurrently": "^3.4.0",
|
||||
"cross-spawn": "^5.1.0",
|
||||
|
@ -116,6 +118,7 @@
|
|||
"image-size": "^0.5.1",
|
||||
"jasmine-core": "^2.8.0",
|
||||
"jasmine-spec-reporter": "^4.1.0",
|
||||
"jasmine-ts": "^0.2.1",
|
||||
"jsdom": "^9.12.0",
|
||||
"karma": "^1.7.0",
|
||||
"karma-chrome-launcher": "^2.1.1",
|
||||
|
@ -145,6 +148,7 @@
|
|||
"unist-util-visit-parents": "^1.1.1",
|
||||
"vrsource-tslint-rules": "^4.0.1",
|
||||
"watchr": "^3.0.1",
|
||||
"xregexp": "^4.0.0",
|
||||
"yargs": "^7.0.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,9 @@ fi
|
|||
# Include any mode-specific files
|
||||
cp -rf src/extra-files/$deployEnv/. dist/
|
||||
|
||||
# Check that the redirects are setup correctly
|
||||
yarn redirects-test
|
||||
|
||||
# Check payload size
|
||||
yarn payload-size
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import { FirebaseGlob } from './FirebaseGlob';
|
||||
|
||||
describe('FirebaseGlob', () => {
|
||||
|
||||
describe('test', () => {
|
||||
it('should match * parts', () => {
|
||||
testGlob('asdf/*.jpg',
|
||||
['asdf/asdf.jpg', 'asdf/asdf_asdf.jpg', 'asdf/.jpg'],
|
||||
['asdf/asdf/asdf.jpg', 'xxxasdf/asdf.jpgxxx']);
|
||||
});
|
||||
|
||||
it('should match ** parts', () => {
|
||||
testGlob('asdf/**.jpg',
|
||||
['asdf/asdf.jpg', 'asdf/asdf_asdf.jpg', 'asdf/asdf/asdf.jpg', 'asdf/asdf/asdf/asdf/asdf.jpg'],
|
||||
['/asdf/asdf.jpg', 'asdff/asdf.jpg', 'xxxasdf/asdf.jpgxxx']);
|
||||
|
||||
testGlob('**/*.js',
|
||||
['asdf/asdf.js', 'asdf/asdf/asdfasdf_asdf.js', '/asdf/asdf.js', '/asdf/aasdf-asdf.2.1.4.js'],
|
||||
['/asdf/asdf.jpg', 'asdf.js']);
|
||||
});
|
||||
|
||||
it('should match groups', () => {
|
||||
testGlob('asdf/*.(jpg|jpeg)',
|
||||
['asdf/asdf.jpg', 'asdf/asdf_asdf.jpeg'],
|
||||
['/asdf/asdf.jpg', 'asdff/asdf.jpg']);
|
||||
});
|
||||
|
||||
it('should match named parts', () => {
|
||||
testGlob('/api/:package/:api-*',
|
||||
['/api/common/NgClass-directive', '/api/core/Renderer-class'],
|
||||
['/moo/common/NgClass-directive', '/api/common/', '/api/common/NgClass']);
|
||||
});
|
||||
|
||||
it('should match wildcard named parts', () => {
|
||||
testGlob('/api/:rest*',
|
||||
['/api/a', '/api/a/b'],
|
||||
['/apx/a', '/apx/a/b']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('match', () => {
|
||||
it('should extract the named parts', () => {
|
||||
const glob = new FirebaseGlob('/api/:package/:api-*');
|
||||
const match: any = glob.match('/api/common/NgClass-directive');
|
||||
expect(match).toEqual({package: 'common', api: 'NgClass'});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function testGlob(pattern: string, matches: string[], nonMatches: string[]) {
|
||||
const glob = new FirebaseGlob(pattern);
|
||||
matches.forEach(url => expect(glob.test(url)).toBe(true, url));
|
||||
nonMatches.forEach(url => expect(glob.test(url)).toBe(false, url));
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import * as XRegExp from 'xregexp';
|
||||
|
||||
const questionExpr = /\?([^(])/g;
|
||||
const catchAllNamedMatchExpr = /\/:([A-Za-z]+)\*/g
|
||||
const namedMatchExpr = /\/:([A-Za-z]+)([^/]*)/g
|
||||
const wildcardSegmentExpr = /(^\/).🐷\//;
|
||||
|
||||
export class FirebaseGlob {
|
||||
pattern: string;
|
||||
regex: XRegExp;
|
||||
constructor(glob: string) {
|
||||
const pattern = glob
|
||||
.replace('.', '\\.')
|
||||
.replace(questionExpr, '[^/]$1')
|
||||
.replace(catchAllNamedMatchExpr, '/(?<$1>.+)')
|
||||
.replace(namedMatchExpr, '/(?<$1>[^/]+)$2')
|
||||
.replace('**', '.🐷')
|
||||
.replace('*', '[^/]*')
|
||||
.replace(wildcardSegmentExpr, '(?:$1|/.*/)')
|
||||
.replace('.🐷', '.*');
|
||||
this.pattern = `^${pattern}$`;
|
||||
this.regex = XRegExp(this.pattern);
|
||||
}
|
||||
|
||||
test(url: string) {
|
||||
return XRegExp.test(url, this.regex);
|
||||
}
|
||||
|
||||
match(url: string) {
|
||||
const match = XRegExp.exec(url, this.regex);
|
||||
if (match) {
|
||||
const result = {};
|
||||
const names = (this.regex as any).xregexp.captureNames || [];
|
||||
names.forEach(name => result[name] = match[name]);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { FirebaseRedirect } from './FirebaseRedirect';
|
||||
|
||||
describe('FirebaseRedirect', () => {
|
||||
describe('replace', () => {
|
||||
it('should inject the named captures into the destination', () => {
|
||||
const redirect = new FirebaseRedirect('/api/:package/:api-*', '<:package><:api>');
|
||||
const newUrl = redirect.replace('/api/common/NgClass-directive');
|
||||
expect(newUrl).toEqual('<common><NgClass>');
|
||||
});
|
||||
|
||||
it('should handle empty ** sections', () => {
|
||||
const redirect2 = new FirebaseRedirect('/**/a/b', '/xxx');
|
||||
expect(redirect2.replace('/a/b')).toEqual('/xxx');
|
||||
});
|
||||
|
||||
it('should return `undefined` if the redirect failed to match', () => {
|
||||
const redirect = new FirebaseRedirect('/api/:package/:api-*', '<:package><:api>');
|
||||
const newUrl = redirect.replace('/common/NgClass-directive');
|
||||
expect(newUrl).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import * as XRegExp from 'xregexp';
|
||||
import { FirebaseGlob } from './FirebaseGlob';
|
||||
|
||||
export class FirebaseRedirect {
|
||||
glob = new FirebaseGlob(this.source);
|
||||
constructor(public source: string, public destination: string) {}
|
||||
|
||||
replace(url: string) {
|
||||
const match = this.glob.match(url);
|
||||
if (match) {
|
||||
const replacers = Object.keys(match).map(name => [ XRegExp(`:${name}`, 'g'), match[name] ]);
|
||||
return XRegExp.replaceEach(this.destination, replacers);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import { FirebaseRedirector } from './FirebaseRedirector';
|
||||
|
||||
describe('FirebaseRedirector', () => {
|
||||
it('should replace with the first matching redirect', () => {
|
||||
const redirector = new FirebaseRedirector([
|
||||
{ source: '/a/b/c', destination: '/X/Y/Z' },
|
||||
{ source: '/a/:foo/c', destination: '/X/:foo/Z' },
|
||||
{ source: '/**/:foo/c', destination: '/A/:foo/zzz' },
|
||||
]);
|
||||
expect(redirector.redirect('/a/b/c')).toEqual('/X/Y/Z');
|
||||
expect(redirector.redirect('/a/moo/c')).toEqual('/X/moo/Z');
|
||||
expect(redirector.redirect('/x/y/a/b/c')).toEqual('/A/b/zzz');
|
||||
expect(redirector.redirect('/x/y/c')).toEqual('/A/y/zzz');
|
||||
});
|
||||
|
||||
it('should return the original url if no redirect matches', () => {
|
||||
const redirector = new FirebaseRedirector([
|
||||
{ source: 'x', destination: 'X' },
|
||||
{ source: 'y', destination: 'Y' },
|
||||
{ source: 'z', destination: 'Z' },
|
||||
]);
|
||||
expect(redirector.redirect('a')).toEqual('a');
|
||||
});
|
||||
|
||||
it('should recursively redirect', () => {
|
||||
const redirector = new FirebaseRedirector([
|
||||
{ source: 'a', destination: 'b' },
|
||||
{ source: 'b', destination: 'c' },
|
||||
{ source: 'c', destination: 'd' },
|
||||
]);
|
||||
expect(redirector.redirect('a')).toEqual('d');
|
||||
});
|
||||
|
||||
it('should throw if stuck in an infinite loop', () => {
|
||||
const redirector = new FirebaseRedirector([
|
||||
{ source: 'a', destination: 'b' },
|
||||
{ source: 'b', destination: 'c' },
|
||||
{ source: 'c', destination: 'a' },
|
||||
]);
|
||||
expect(() => redirector.redirect('a')).toThrowError('infinite redirect loop');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
import { FirebaseRedirect } from './FirebaseRedirect';
|
||||
|
||||
export interface FirebaseRedirectConfig {
|
||||
source: string;
|
||||
destination: string;
|
||||
}
|
||||
|
||||
export class FirebaseRedirector {
|
||||
private redirects: FirebaseRedirect[];
|
||||
constructor(redirects: FirebaseRedirectConfig[]) {
|
||||
this.redirects = redirects.map(redirect => new FirebaseRedirect(redirect.source, redirect.destination));
|
||||
}
|
||||
|
||||
redirect(url: string) {
|
||||
let ttl = 50;
|
||||
while(ttl > 0) {
|
||||
const newUrl = this.doRedirect(url);
|
||||
if (newUrl === url) {
|
||||
return url;
|
||||
} else {
|
||||
url = newUrl;
|
||||
ttl--;
|
||||
}
|
||||
}
|
||||
throw new Error('infinite redirect loop')
|
||||
}
|
||||
private doRedirect(url: string) {
|
||||
for(let i = 0; i < this.redirects.length; i++) {
|
||||
const newUrl = this.redirects[i].replace(url);
|
||||
if (newUrl !== undefined) {
|
||||
return newUrl;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
/api/api/core/ElementRef api/core/ElementRef
|
||||
/api/common/Control-class /api/forms/FormControl
|
||||
/api/common/CORE_DIRECTIVES /api/common/CommonModule
|
||||
/api/common/DatePipe-class /api/common/DatePipe
|
||||
/api/common/NgClass-directive.html /api/common/NgClass
|
||||
/api/common/NgFor-directive.html /api/common/NgForOf
|
||||
/api/common/NgModel-directive /api/forms/NgModel
|
||||
/api/common/SelectControlValueAccessor-directive /api/forms/SelectControlValueAccessor
|
||||
/api/common/SlicePipe-class.html /api/common/SlicePipe
|
||||
/api/core/AnimationStateDeclarationMetadata /api/animation
|
||||
/api/core/DoCheck-interface.html /api/core/DoCheck
|
||||
/api/core/HostBinding-var /api/core/HostBinding
|
||||
/api/core/OpaqueToken-class /api/core/OpaqueToken
|
||||
/api/core/OptionalMetadata-class /api/core/OptionalMetadata
|
||||
/api/core/PLATFORM_PIPES /api/common
|
||||
/api/core/Provider-class.html /api/core/Provider
|
||||
/api/core/Renderer-class /api/core/Renderer
|
||||
/api/core/testing/async-function /api/core/testing/async
|
||||
/api/core/testing/index/async-function /api/core/testing/async
|
||||
/api/core/testing/index/TestBed-class.html /api/core/testing/TestBed
|
||||
/api/core/testing/inject-function /api/core/testing/inject
|
||||
/api/core/testing/inject-function.html /api/core/testing/inject
|
||||
/api/http/Headers-class /api/http/Headers
|
||||
/api/http/Headers-class.html /api/http/Headers
|
||||
/api/http/HTTP_PROVIDERS-let /api/http/HttpModule
|
||||
/api/http/testing/index/MockBackend-class /api/http/testing/MockBackend
|
||||
/api/http/testing/index/MockBackend-class.html /api/http/testing/MockBackend
|
||||
/api/platform-browser-dynamic/testing/index/platformBrowserDynamicTesting-let.html /api/platform-browser-dynamic/testing/platformBrowserDynamicTesting
|
||||
/api/platform-browser/AnimationDriver /api/animations/browser/AnimationDriver
|
||||
/api/router/Route-class /api/router/Route
|
||||
/api/router/RouterLink-directive /api/router/RouterLink
|
||||
/api/testing/tick-function /api/core/testing/tick
|
||||
/api/upgrade/static/downgradeComponent-function /api/upgrade/static/downgradeComponent
|
||||
/api/upgrade/static/downgradeComponent-function.html /api/upgrade/static/downgradeComponent
|
||||
/api/upgrade/static/index/downgradeComponent-function /api/upgrade/static/downgradeComponent
|
||||
/api/upgrade/static/UpgradeModule-class /api/upgrade/static/UpgradeModule
|
||||
/docs/js/latest/api/ /api/*
|
||||
/docs/js/latest/api/animate/AnimationBuilder-class /api/animate/AnimationBuilder
|
||||
/docs/js/latest/api/animate/CssAnimationBuilder-class.html /api/animate/CssAnimationBuilder
|
||||
/docs/js/latest/api/animations/index/trigger-function /api/animations/trigger
|
||||
/docs/js/latest/api/common/ControlGroup-class.html /api/forms/FormGroup
|
||||
/docs/js/latest/api/common/index/DatePipe-pipe /api/common/DatePipe
|
||||
/docs/js/latest/api/common/index/Location-class.html /api/common/Location
|
||||
/docs/js/latest/api/common/index/MaxLengthValidator-directive.html /api/forms/MaxLengthValidator
|
||||
/docs/js/latest/api/common/index/NgFor-directive /api/common/NgForOf
|
||||
/docs/js/latest/api/common/index/NgFor-directive.html /api/common/NgForOf
|
||||
/docs/js/latest/api/common/index/NgFor-type-alias /api/common/NgForOf
|
||||
/docs/js/latest/api/common/index/NgFor-type-alias.html /api/common/NgForOf
|
||||
/docs/js/latest/api/common/index/NgTemplateOutlet-directive /api/common/NgTemplateOutlet
|
||||
/docs/js/latest/api/common/NgStyle-directive /api/common/NgStyle
|
||||
/docs/js/latest/api/core/DynamicComponentLoader-class.html /api/core/DynamicComponentLoader
|
||||
/docs/js/latest/api/core/HostListener-var /api/core/HostListener
|
||||
/docs/js/latest/api/core/index/AfterViewChecked-class /api/core/AfterViewChecked
|
||||
/docs/js/latest/api/core/index/AnimationStateTransitionMetadata-class.html /api/core/AnimationStateTransitionMetadata
|
||||
/docs/js/latest/api/core/index/AnimationStateTransitionMetadata-type-alias /api/core/AnimationStateTransitionMetadata
|
||||
/docs/js/latest/api/core/index/ApplicationModule-class /api/core/ApplicationModule
|
||||
/docs/js/latest/api/core/index/ApplicationRef-class /api/core/ApplicationRef
|
||||
/docs/js/latest/api/core/index/ChangeDetectorRef-class /api/core/ChangeDetectorRef
|
||||
/docs/js/latest/api/core/index/ComponentFactory-class /api/core/ComponentFactory
|
||||
/docs/js/latest/api/core/index/DebugNode-class /api/core/DebugNode
|
||||
/docs/js/latest/api/core/index/destroyPlatform-function /api/core/destroyPlatform
|
||||
/docs/js/latest/api/core/index/DirectiveMetadata-class /api/core/Directive
|
||||
/docs/js/latest/api/core/index/ErrorHandler-class /api/core/ErrorHandler
|
||||
/docs/js/latest/api/core/index/EventEmitter-class /api/core/EventEmitter
|
||||
/docs/js/latest/api/core/index/EventEmitter-class.html /api/core/EventEmitter
|
||||
/docs/js/latest/api/core/index/getPlatform-function /api/core/getPlatform
|
||||
/docs/js/latest/api/core/index/NgModule-interface /api/core/NgModule
|
||||
/docs/js/latest/api/core/index/NgModuleRef-class /api/core/NgModuleRef
|
||||
/docs/js/latest/api/core/index/NgModuleRef-class.html /api/core/NgModuleRef
|
||||
/docs/js/latest/api/core/index/OnInit-class /api/core/OnInit
|
||||
/docs/js/latest/api/core/index/OnInit-class.html /api/core/OnInit
|
||||
/docs/js/latest/api/core/index/OnInit-interface /api/core/OnInit
|
||||
/docs/js/latest/api/core/index/PlatformRef-class /api/core/PlatformRef
|
||||
/docs/js/latest/api/core/index/QueryList-class.html /api/core/QueryList
|
||||
/docs/js/latest/api/core/index/RenderComponentType-class /api/core/RenderComponentType
|
||||
/docs/js/latest/api/core/index/Renderer2-class.html /api/core/Renderer2
|
||||
/docs/js/latest/api/core/index/state-function.html /api/core/state
|
||||
/docs/js/latest/api/core/index/transition-function.html /api/core/transition
|
||||
/docs/js/latest/api/core/index/trigger-function /api/core/trigger
|
||||
/docs/js/latest/api/core/index/trigger-function.html /api/core/trigger
|
||||
/docs/js/latest/api/core/index/ViewChild-decorator /api/core/ViewChild
|
||||
/docs/js/latest/api/core/index/wtfLeave-let /api/core/wtfLeave
|
||||
/docs/js/latest/api/core/Injector-class.html /api/core/Injector
|
||||
/docs/js/latest/api/core/Query-var /api/core/Query
|
||||
/docs/js/latest/api/core/ResolvedProvider-interface.html /api/core/ResolvedProvider
|
||||
/docs/js/latest/api/core/testing/index/TestBed-class /api/core/testing/TestBed
|
||||
/docs/js/latest/api/core/testing/index/tick-function /api/core/testing/tick
|
||||
/docs/js/latest/api/core/testing/index/tick-function.html /api/core/testing/tick
|
||||
/docs/js/latest/api/core/ViewContainerRef-class.html /api/core/ViewContainerRef
|
||||
/docs/js/latest/api/forms/index/AbstractControl-class /api/forms/AbstractControl
|
||||
/docs/js/latest/api/forms/index/AbstractControl-class.html /api/forms/AbstractControl
|
||||
/docs/js/latest/api/forms/index/FormArray-class.html /api/forms/FormArray
|
||||
/docs/js/latest/api/forms/index/FormBuilder-class.html /api/forms/FormBuilder
|
||||
/docs/js/latest/api/forms/index/NG_VALIDATORS-let /api/forms/NG_VALIDATORS
|
||||
/docs/js/latest/api/forms/index/Validator-interface.html /api/forms/Validator
|
||||
/docs/js/latest/api/http/ConnectionBackend-class /api/http/ConnectionBackend
|
||||
/docs/js/latest/api/http/index/Http-class.html /api/http/Http
|
||||
/docs/js/latest/api/http/index/Jsonp-class.html /api/http/Jsonp
|
||||
/docs/js/latest/api/http/index/ResponseOptions-class.html /api/http/ResponseOptions
|
||||
/docs/js/latest/api/http/index/URLSearchParams-class /api/http/URLSearchParams
|
||||
/docs/js/latest/api/http/index/XHRConnection-class /api/http/XHRConnection
|
||||
/docs/js/latest/api/http/index/XHRConnection-class.html /api/http/XHRConnection
|
||||
/docs/js/latest/api/http/testing/index/MockConnection-class.html /api/http/testing/MockConnection
|
||||
/docs/js/latest/api/http/testing/MockBackend-class /api/http/testing/MockBackend
|
||||
/docs/js/latest/api/platform-browser-dynamic/index/platformBrowserDynamic-let.html /api/platform-browser-dynamic/platformBrowserDynamic
|
||||
/docs/js/latest/api/platform-browser-dynamic/testing/index/BrowserDynamicTestingModule-class.html /api/platform-browser-dynamic/testing/BrowserDynamicTestingModule
|
||||
/docs/js/latest/api/platform-browser/animations/index/BrowserAnimationsModule-class /api/platform-browser/animations/BrowserAnimationsModule-class
|
||||
/docs/js/latest/api/platform-browser/animations/index/BrowserAnimationsModule-class.html /api/platform-browser/animations/BrowserAnimationsModule-class.html
|
||||
/docs/js/latest/api/platform-browser/animations/index/NoopAnimationsModule-class.html /api/platform-browser/animations/NoopAnimationsModule-class.html
|
||||
/docs/js/latest/api/platform-browser/index/DomSanitizer-class /api/platform-browser/DomSanitizer
|
||||
/docs/js/latest/api/platform-browser/index/Meta-class /api/platform-browser/Meta
|
||||
/docs/js/latest/api/platform-browser/index/MetaDefinition-type-alias /api/platform-browser/MetaDefinition
|
||||
/docs/js/latest/api/platform-browser/index/SafeUrl-interface /api/platform-browser/SafeUrl
|
||||
/docs/js/latest/api/platform-browser/index/Title-class /api/platform-browser/Title
|
||||
/docs/js/latest/api/platform-browser/index/Title-class.html /api/platform-browser/Title
|
||||
/docs/js/latest/api/platform-server/index/PlatformState-class /api/platform-server/PlatformState
|
||||
/docs/js/latest/api/platform-server/index/PlatformState-class.html /api/platform-server/PlatformState
|
||||
/docs/js/latest/api/platform-webworker /api/platform-webworker
|
||||
/docs/js/latest/api/platform-webworker/index/MessageBus-class /api/platform-webworker/MessageBus
|
||||
/docs/js/latest/api/router/index/ActivatedRoute-interface /api/router/ActivatedRoute
|
||||
/docs/js/latest/api/router/index/CanActivate-interface.html /api/router/CanActivate
|
||||
/docs/js/latest/api/router/index/CanActivateChild-interface /api/router/CanActivateChild
|
||||
/docs/js/latest/api/router/index/CanDeactivate-interface.html /api/router/CanDeactivate
|
||||
/docs/js/latest/api/router/index/CanLoad-interface /api/router/CanLoad
|
||||
/docs/js/latest/api/router/index/CanLoad-interface.html /api/router/CanLoad
|
||||
/docs/js/latest/api/router/index/NavigationEnd-class /api/router/NavigationEnd
|
||||
/docs/js/latest/api/router/index/provideRoutes-function /api/router/provideRoutes
|
||||
/docs/js/latest/api/router/index/provideRoutes-function.html /api/router/provideRoutes
|
||||
/docs/js/latest/api/router/index/Router-class /api/router/Router
|
||||
/docs/js/latest/api/router/index/RouterLink-directive /api/router/RouterLink
|
||||
/docs/js/latest/api/router/index/Routes-type-alias /api/router/Routes
|
||||
/docs/js/latest/api/router/index/UrlSegment-class /api/router/UrlSegment
|
||||
/docs/js/latest/api/router/index/UrlSerializer-class.html /api/router/UrlSerializer
|
||||
/docs/js/latest/api/router/Instruction-class /api/router/Instruction
|
||||
/docs/js/latest/api/router/Location-class /api/router/Location
|
||||
/docs/js/latest/api/router/OnActivate-interface /api/router/OnActivate
|
||||
/docs/js/latest/api/router/Redirect-class.html /api/router/Redirect
|
||||
/docs/js/latest/api/router/RouteDefinition-interface.html /api/router/RouteDefinition
|
||||
/docs/js/latest/api/router/RouteParams-class /api/router/RouteParams
|
||||
/docs/js/latest/api/router/RouteParams-class.html /api/router/RouteParams
|
||||
/docs/js/latest/api/router/Router-class.html /api/router/Router
|
||||
/docs/js/latest/api/router/testing /api/router/testing
|
||||
/docs/js/latest/api/upgrade/index/UpgradeAdapter-class.html /api/upgrade/UpgradeAdapter
|
||||
/docs/js/latest/api/upgrade/static/UpgradeModule-class /api/upgrade/static/UpgradeModule
|
||||
/docs/js/latest/api/upgrade/static/UpgradeModule-class.html /api/upgrade/static/UpgradeModule
|
||||
/docs/js/latest/cookbook/ts-to-js.html https://github.com/angular/angular/blob/master/aio/content/guide/change-log.md#es6--described-in-typescript-to-javascript-2016-11-14
|
||||
/docs/js/latest/glossary /guide/glossary
|
||||
/docs/js/latest/guide/ /guide
|
||||
/docs/js/latest/guide/lifecycle-hooks /guide/lifecycle-hooks
|
||||
/docs/js/latest/guide/ngmodule /guide/ngmodule*
|
||||
/docs/js/latest/resources /resources*
|
||||
/docs/latest/tutorial /tutorial*
|
||||
/docs/styleguide /guide/styleguide
|
||||
/docs/styleguide.html /guide/styleguide
|
||||
/docs/ts/latest/api/core/HostBinding-var.html /api/core/HostBinding
|
||||
/docs/ts/latest/api/core/index/BaseException-class.html /api/core/BaseException
|
||||
/docs/ts/latest/api/core/index/PLATFORM_PIPES-let.html /api/common
|
||||
/docs/ts/latest/api/core/OnInit-interface.html /api/core/OnInit
|
||||
/docs/ts/latest/api/core/OpaqueToken-class.html /api/core/OpaqueToken
|
||||
/docs/ts/latest/api/core/OptionalMetadata-class.html /api/core/OptionalMetadata
|
||||
/docs/ts/latest/api/core/testing/index/async-function.html /api/core/testing/async
|
||||
/docs/ts/latest/api/core/testing/index/fakeAsync-function.html /api/core/testing/fakeAsync
|
||||
/docs/ts/latest/api/core/testing/index/TestComponentRenderer-class.html /api/core/testing/TestComponentRenderer
|
||||
/docs/ts/latest/api/core/testing/index/tick-function.html /api/core/testing/tick
|
||||
/docs/ts/latest/api/http/Connection-class.html /api/http/Connection
|
||||
/docs/ts/latest/api/http/testing/index/MockBackend-class.html /api/http/testing/MockBackend
|
||||
/docs/ts/latest/api/http/testing/index/MockConnection-class.html /api/http/testing/MockConnection
|
||||
/docs/ts/latest/api/platform-browser-dynamic/index/workerAppDynamicPlatform-let.html /api/platform-browser-dynamic/workerAppDynamicPlatform
|
||||
/docs/ts/latest/api/testing/fakeAsync-function.html /api/core/testing/fakeAsync
|
||||
/docs/ts/latest/cookbook/ts-to-js.html https://github.com/angular/angular/blob/master/aio/content/guide/change-log.md#es6--described-in-typescript-to-javascript-2016-11-14
|
||||
/guide/learning-angular /guide/quickstart
|
||||
/guide/learning-angular.html /guide/quickstart
|
||||
/news https://blog.angular.io/
|
||||
/news.html https://blog.angular.io/
|
||||
/testing /guide/testing
|
||||
/testing/first-app-tests.html /guide/testing
|
|
@ -0,0 +1,50 @@
|
|||
const { readFileSync } = require('fs');
|
||||
const path = require('canonical-path');
|
||||
const cjson = require('cjson');
|
||||
|
||||
import { FirebaseRedirector, FirebaseRedirectConfig } from './FirebaseRedirector';
|
||||
|
||||
|
||||
describe('sitemap urls', () => {
|
||||
loadSitemapUrls().forEach(url => {
|
||||
it('should not redirect any urls in the sitemap', () => {
|
||||
expect(getRedirector().redirect(url)).toEqual(url);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('redirected urls', () => {
|
||||
loadLegacyUrls().forEach(urlPair => {
|
||||
it('should redirect the legacy urls', () => {
|
||||
const redirector = getRedirector();
|
||||
expect(redirector.redirect(urlPair[0])).not.toEqual(urlPair[0]);
|
||||
if (urlPair[1]) {
|
||||
expect(redirector.redirect(urlPair[0])).toEqual(urlPair[1]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getRedirector() {
|
||||
return new FirebaseRedirector(loadRedirects());
|
||||
}
|
||||
|
||||
function loadRedirects(): FirebaseRedirectConfig[] {
|
||||
const pathToFirebaseJSON = path.resolve(__dirname, '../../firebase.json');
|
||||
const contents = cjson.load(pathToFirebaseJSON);
|
||||
return contents.hosting.redirects;
|
||||
}
|
||||
|
||||
function loadSitemapUrls() {
|
||||
const pathToSiteMap = path.resolve(__dirname, '../../src/generated/sitemap.xml');
|
||||
const xml = readFileSync(pathToSiteMap, 'utf8');
|
||||
const urls: string[] = [];
|
||||
xml.replace(/<loc>([^<]+)<\/loc>/g, (_, loc) => urls.push(loc.replace('%%DEPLOYMENT_HOST%%', '')));
|
||||
return urls;
|
||||
}
|
||||
|
||||
function loadLegacyUrls() {
|
||||
const pathToLegacyUrls = path.resolve(__dirname, 'URLS_TO_REDIRECT.txt');
|
||||
const urls = readFileSync(pathToLegacyUrls, 'utf8').split('\n').map(line => line.split('\t'));
|
||||
return urls;
|
||||
}
|
|
@ -1426,6 +1426,12 @@ cjson@^0.3.1:
|
|||
dependencies:
|
||||
json-parse-helpfulerror "^1.0.3"
|
||||
|
||||
cjson@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/cjson/-/cjson-0.5.0.tgz#a0f48601e016164dfb2c6d891e380c96cada9839"
|
||||
dependencies:
|
||||
json-parse-helpfulerror "^1.0.3"
|
||||
|
||||
clap@^1.0.9:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
|
||||
|
@ -4634,6 +4640,15 @@ jasmine-spec-reporter@^4.1.0:
|
|||
dependencies:
|
||||
colors "1.1.2"
|
||||
|
||||
jasmine-ts@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/jasmine-ts/-/jasmine-ts-0.2.1.tgz#7fe5911d98ea22cc257efe98f9728ab66ac0e90e"
|
||||
dependencies:
|
||||
jasmine "^2.6.0"
|
||||
ts-node "^3.2.0"
|
||||
typescript "^2.4.1"
|
||||
yargs "^8.0.2"
|
||||
|
||||
jasmine@^2.5.3, jasmine@^2.6.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e"
|
||||
|
@ -8351,7 +8366,7 @@ tryit@^1.0.1:
|
|||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
|
||||
|
||||
ts-node@^3.0.2, ts-node@^3.3.0:
|
||||
ts-node@^3.0.2, ts-node@^3.2.0, ts-node@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.3.0.tgz#c13c6a3024e30be1180dd53038fc209289d4bf69"
|
||||
dependencies:
|
||||
|
@ -8445,14 +8460,14 @@ typescript@2.4:
|
|||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.2.tgz#f8395f85d459276067c988aa41837a8f82870844"
|
||||
|
||||
typescript@^2.4.1, typescript@~2.6.1:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
|
||||
|
||||
typescript@^2.5.3:
|
||||
version "2.5.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.3.tgz#df3dcdc38f3beb800d4bc322646b04a3f6ca7f0d"
|
||||
|
||||
typescript@~2.6.1:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
|
||||
|
||||
uglify-es@^3.3.4:
|
||||
version "3.3.5"
|
||||
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.5.tgz#cf7e695da81999f85196b15e2978862f13212f88"
|
||||
|
@ -9294,6 +9309,10 @@ xmlhttprequest-ssl@1.5.3:
|
|||
version "1.5.3"
|
||||
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d"
|
||||
|
||||
xregexp@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
|
||||
|
||||
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
|
|
Loading…
Reference in New Issue