123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- // Copyright (c) Jupyter Development Team.
- // Distributed under the terms of the Modified BSD License.
- import {
- ABCWidgetFactory,
- Base64ModelFactory,
- DocumentRegistry,
- DocumentWidget,
- IDocumentWidget
- } from '@jupyterlab/docregistry';
- import { toArray } from '@lumino/algorithm';
- import { UUID } from '@lumino/coreutils';
- import { DisposableDelegate, IDisposable } from '@lumino/disposable';
- import { Widget } from '@lumino/widgets';
- class WidgetFactory extends ABCWidgetFactory<IDocumentWidget> {
- protected createNewWidget(
- context: DocumentRegistry.Context
- ): IDocumentWidget {
- const content = new Widget();
- const widget = new DocumentWidget({ content, context });
- widget.addClass('WidgetFactory');
- return widget;
- }
- }
- class WidgetExtension implements DocumentRegistry.WidgetExtension {
- createNew(widget: Widget, context: DocumentRegistry.Context): IDisposable {
- return new DisposableDelegate(() => undefined);
- }
- }
- function createFactory(modelName?: string) {
- return new WidgetFactory({
- name: UUID.uuid4(),
- modelName: modelName || 'text',
- fileTypes: ['text', 'foobar', 'baz'],
- defaultFor: ['text', 'foobar'],
- defaultRendered: ['baz']
- });
- }
- describe('docregistry/registry', () => {
- describe('DocumentRegistry', () => {
- let registry: DocumentRegistry;
- beforeEach(() => {
- registry = new DocumentRegistry();
- registry.addFileType({
- name: 'foobar',
- extensions: ['.foo.bar']
- });
- registry.addFileType({
- name: 'baz',
- extensions: ['.baz']
- });
- });
- afterEach(() => {
- registry.dispose();
- });
- describe('#isDisposed', () => {
- it('should get whether the registry has been disposed', () => {
- expect(registry.isDisposed).toBe(false);
- registry.dispose();
- expect(registry.isDisposed).toBe(true);
- });
- });
- describe('#dispose()', () => {
- it('should dispose of the resources held by the registry', () => {
- registry.addFileType({ name: 'notebook', extensions: ['.ipynb'] });
- registry.dispose();
- expect(registry.isDisposed).toBe(true);
- });
- it('should be safe to call multiple times', () => {
- registry.dispose();
- registry.dispose();
- expect(registry.isDisposed).toBe(true);
- });
- });
- describe('#addWidgetFactory()', () => {
- it('should add the widget factory to the registry', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- expect(registry.getWidgetFactory(factory.name)).toBe(factory);
- expect(registry.getWidgetFactory(factory.name.toUpperCase())).toBe(
- factory
- );
- });
- it('should become the global default if `*` is given as a defaultFor', () => {
- const factory = new WidgetFactory({
- name: 'global',
- fileTypes: ['*'],
- defaultFor: ['*']
- });
- registry.addWidgetFactory(factory);
- expect(registry.defaultWidgetFactory('*').name).toBe('global');
- });
- it('should override an existing global default', () => {
- registry.addWidgetFactory(
- new WidgetFactory({
- name: 'global',
- fileTypes: ['*'],
- defaultFor: ['*']
- })
- );
- const factory = new WidgetFactory({
- name: 'bar',
- fileTypes: ['*'],
- defaultFor: ['*']
- });
- registry.addWidgetFactory(factory);
- expect(registry.defaultWidgetFactory('*').name).toBe('bar');
- });
- it('should override an existing extension default', () => {
- registry.addWidgetFactory(createFactory());
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(factory);
- });
- it('should be removed from the registry when disposed', () => {
- const factory = createFactory();
- const disposable = registry.addWidgetFactory(factory);
- disposable.dispose();
- expect(registry.getWidgetFactory('test')).toBeUndefined();
- });
- it('should throw for an invalid factory name', () => {
- expect(() => {
- registry.addWidgetFactory(
- new WidgetFactory({
- name: 'default',
- fileTypes: [],
- defaultFor: []
- })
- );
- }).toThrowError(/Invalid/);
- expect(() => {
- registry.addWidgetFactory(
- new WidgetFactory({
- name: '',
- fileTypes: [],
- defaultFor: []
- })
- );
- }).toThrowError(/Invalid/);
- });
- });
- describe('#addModelFactory()', () => {
- it('should add the model factory to the registry', () => {
- const factory = new Base64ModelFactory();
- registry.addModelFactory(factory);
- });
- it('should be a no-op a factory with the given `name` is already registered', () => {
- const factory = new Base64ModelFactory();
- registry.addModelFactory(factory);
- const disposable = registry.addModelFactory(new Base64ModelFactory());
- disposable.dispose();
- });
- it('should be a no-op if the same factory is already registered', () => {
- const factory = new Base64ModelFactory();
- registry.addModelFactory(factory);
- const disposable = registry.addModelFactory(factory);
- disposable.dispose();
- });
- it('should be removed from the registry when disposed', () => {
- const factory = new Base64ModelFactory();
- const disposable = registry.addModelFactory(factory);
- disposable.dispose();
- });
- });
- describe('#addWidgetExtension()', () => {
- it('should add a widget extension to the registry', () => {
- const extension = new WidgetExtension();
- registry.addWidgetExtension('foo', extension);
- expect(registry.widgetExtensions('foo').next()).toBe(extension);
- });
- it('should be a no-op if the extension is already registered for a given widget factory', () => {
- const extension = new WidgetExtension();
- registry.addWidgetExtension('foo', extension);
- const disposable = registry.addWidgetExtension('foo', extension);
- disposable.dispose();
- expect(registry.widgetExtensions('foo').next()).toBe(extension);
- });
- it('should be removed from the registry when disposed', () => {
- const extension = new WidgetExtension();
- const disposable = registry.addWidgetExtension('foo', extension);
- disposable.dispose();
- expect(toArray(registry.widgetExtensions('foo')).length).toBe(0);
- });
- });
- describe('#addFileType()', () => {
- it('should add a file type to the document registry', () => {
- registry = new DocumentRegistry({ initialFileTypes: [] });
- const fileType = { name: 'notebook', extensions: ['.ipynb'] };
- registry.addFileType(fileType);
- expect(registry.fileTypes().next()!.name).toBe(fileType.name);
- });
- it('should be removed from the registry when disposed', () => {
- registry = new DocumentRegistry({ initialFileTypes: [] });
- const fileType = { name: 'notebook', extensions: ['.ipynb'] };
- const disposable = registry.addFileType(fileType);
- disposable.dispose();
- expect(toArray(registry.fileTypes()).length).toBe(0);
- });
- it('should be a no-op if a file type of the same name is registered', () => {
- registry = new DocumentRegistry({ initialFileTypes: [] });
- const fileType = { name: 'notebook', extensions: ['.ipynb'] };
- registry.addFileType(fileType);
- const disposable = registry.addFileType(fileType);
- disposable.dispose();
- expect(registry.fileTypes().next()!.name).toBe(fileType.name);
- });
- });
- describe('#preferredWidgetFactories()', () => {
- beforeEach(() => {
- registry.addFileType({
- name: 'tablejson',
- extensions: ['.table.json']
- });
- });
- it('should give the valid registered widget factories', () => {
- expect(toArray(registry.preferredWidgetFactories('foo.txt'))).toEqual(
- []
- );
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const gFactory = new WidgetFactory({
- name: 'global',
- fileTypes: ['*'],
- defaultFor: ['*']
- });
- registry.addWidgetFactory(gFactory);
- const factories = registry.preferredWidgetFactories('a.foo.bar');
- expect(toArray(factories)).toEqual([factory, gFactory]);
- });
- it('should not list a factory whose model is not registered', () => {
- registry.addWidgetFactory(createFactory('foobar'));
- expect(registry.preferredWidgetFactories('a.foo.bar').length).toEqual(
- 0
- );
- });
- it('should select the factory for a given extension', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown']
- });
- registry.addWidgetFactory(mdFactory);
- expect(registry.preferredWidgetFactories('a.txt')[0]).toBe(factory);
- expect(registry.preferredWidgetFactories('a.md')[0]).toBe(mdFactory);
- });
- it('should respect the priority order', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const gFactory = new WidgetFactory({
- name: 'global',
- fileTypes: ['*'],
- defaultFor: ['*']
- });
- registry.addWidgetFactory(gFactory);
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown']
- });
- registry.addWidgetFactory(mdFactory);
- const factories = registry.preferredWidgetFactories('a.txt');
- expect(toArray(factories)).toEqual([factory, gFactory]);
- });
- it('should list a default rendered factory after the default factory', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const gFactory = new WidgetFactory({
- name: 'global',
- fileTypes: ['*'],
- defaultFor: ['*']
- });
- registry.addWidgetFactory(gFactory);
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown'],
- defaultRendered: ['markdown']
- });
- registry.addWidgetFactory(mdFactory);
- const factories = registry.preferredWidgetFactories('a.md');
- expect(factories).toEqual([mdFactory, gFactory]);
- });
- it('should handle multi-part extensions', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const tFactory = new WidgetFactory({
- name: 'table',
- fileTypes: ['tablejson']
- });
- registry.addWidgetFactory(tFactory);
- const jFactory = new WidgetFactory({
- name: 'json',
- fileTypes: ['json']
- });
- registry.addWidgetFactory(jFactory);
- let factories = registry.preferredWidgetFactories('foo.table.json');
- expect(toArray(factories)).toEqual([tFactory, jFactory]);
- factories = registry.preferredWidgetFactories('foo.json');
- expect(toArray(factories)).toEqual([jFactory]);
- });
- it('should handle just a multi-part extension', () => {
- const factory = new WidgetFactory({
- name: 'table',
- fileTypes: ['tablejson']
- });
- registry.addWidgetFactory(factory);
- let factories = registry.preferredWidgetFactories('foo.table.json');
- expect(toArray(factories)).toEqual([factory]);
- factories = registry.preferredWidgetFactories('foo.json');
- expect(toArray(factories)).toEqual([]);
- });
- });
- describe('#defaultWidgetFactory()', () => {
- it('should get the default widget factory for a given extension', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const gFactory = new WidgetFactory({
- name: 'global',
- fileTypes: ['*'],
- defaultFor: ['*']
- });
- registry.addWidgetFactory(gFactory);
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown'],
- defaultFor: ['markdown']
- });
- registry.addWidgetFactory(mdFactory);
- expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(factory);
- expect(registry.defaultWidgetFactory('a.md')).toBe(mdFactory);
- expect(registry.defaultWidgetFactory()).toBe(gFactory);
- });
- });
- describe('#setDefaultWidgetFactory()', () => {
- it('should override the default widget factory for a file type', () => {
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown', 'foobar'],
- defaultFor: []
- });
- registry.addWidgetFactory(mdFactory);
- registry.setDefaultWidgetFactory('foobar', 'markdown');
- expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(mdFactory);
- });
- it('should revert to the default widget factory when unset', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown', 'foobar'],
- defaultFor: []
- });
- registry.addWidgetFactory(mdFactory);
- registry.setDefaultWidgetFactory('foobar', 'markdown');
- registry.setDefaultWidgetFactory('foobar', undefined);
- expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(factory);
- });
- it('should throw if the factory or file type do not exist', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- expect(() => {
- registry.setDefaultWidgetFactory('foobar', 'fake');
- }).toThrowError(/Cannot find/);
- expect(() => {
- registry.setDefaultWidgetFactory('fake', undefined);
- }).toThrowError(/Cannot find/);
- });
- it('should throw if the factory cannot render a file type', () => {
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown'],
- defaultFor: []
- });
- registry.addWidgetFactory(mdFactory);
- expect(() => {
- registry.setDefaultWidgetFactory('foobar', 'markdown');
- }).toThrowError(/cannot view/);
- });
- it('should revert to the default widget factory if the override is removed', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown', 'foobar'],
- defaultFor: []
- });
- const disposable = registry.addWidgetFactory(mdFactory);
- registry.setDefaultWidgetFactory('foobar', 'markdown');
- disposable.dispose();
- expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(factory);
- });
- });
- describe('#defaultRenderedWidgetFactory()', () => {
- it('should get the default rendered widget factory for a given extension', () => {
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown'],
- defaultRendered: ['markdown']
- });
- registry.addWidgetFactory(mdFactory);
- expect(registry.defaultRenderedWidgetFactory('a.baz')).toBe(factory);
- expect(registry.defaultRenderedWidgetFactory('a.md')).toBe(mdFactory);
- });
- it('should get the default widget factory if no default rendered factory is registered', () => {
- const gFactory = new WidgetFactory({
- name: 'global',
- fileTypes: ['*'],
- defaultFor: ['*']
- });
- registry.addWidgetFactory(gFactory);
- expect(registry.defaultRenderedWidgetFactory('a.md')).toBe(gFactory);
- });
- });
- describe('#fileTypes()', () => {
- it('should get the registered file types', () => {
- registry = new DocumentRegistry({ initialFileTypes: [] });
- expect(toArray(registry.fileTypes()).length).toBe(0);
- const fileTypes = [
- { name: 'notebook', extensions: ['.ipynb'] },
- { name: 'python', extensions: ['.py'] },
- { name: 'table', extensions: ['.table.json'] }
- ];
- registry.addFileType(fileTypes[0]);
- registry.addFileType(fileTypes[1]);
- registry.addFileType(fileTypes[2]);
- const values = registry.fileTypes();
- expect(values.next()!.name).toBe(fileTypes[0].name);
- expect(values.next()!.name).toBe(fileTypes[1].name);
- expect(values.next()!.name).toBe(fileTypes[2].name);
- });
- });
- describe('#getFileType()', () => {
- it('should get a file type by name', () => {
- expect(registry.getFileType('notebook')).toBeTruthy();
- expect(registry.getFileType('python')).toBeTruthy();
- expect(registry.getFileType('fizzbuzz')).toBeUndefined();
- });
- });
- describe('#getKernelPreference()', () => {
- it('should get a kernel preference', () => {
- registry.addWidgetFactory(createFactory());
- registry.addWidgetFactory(
- new WidgetFactory({
- name: 'python',
- fileTypes: ['python'],
- preferKernel: true,
- canStartKernel: true
- })
- );
- registry.addWidgetFactory(
- new WidgetFactory({
- name: 'global',
- fileTypes: ['*'],
- defaultFor: ['*']
- })
- );
- let pref = registry.getKernelPreference('.c', 'global');
- expect(pref!.language).toBe('clike');
- expect(pref!.shouldStart).toBe(false);
- expect(pref!.canStart).toBe(false);
- pref = registry.getKernelPreference('.py', 'python');
- expect(pref!.language).toBe('python');
- expect(pref!.shouldStart).toBe(true);
- expect(pref!.canStart).toBe(true);
- pref = registry.getKernelPreference('.py', 'baz');
- expect(pref).toBeUndefined();
- });
- });
- describe('#getModelFactory()', () => {
- it('should get a registered model factory by name', () => {
- const mFactory = new Base64ModelFactory();
- registry.addModelFactory(mFactory);
- expect(registry.getModelFactory('base64')).toBe(mFactory);
- });
- });
- describe('#getWidgetFactory()', () => {
- it('should get a widget factory by name', () => {
- registry.addModelFactory(new Base64ModelFactory());
- const factory = createFactory();
- registry.addWidgetFactory(factory);
- const mdFactory = new WidgetFactory({
- name: 'markdown',
- fileTypes: ['markdown']
- });
- registry.addWidgetFactory(mdFactory);
- expect(registry.getWidgetFactory(factory.name)).toBe(factory);
- expect(registry.getWidgetFactory('markdown')).toBe(mdFactory);
- expect(registry.getWidgetFactory('baz')).toBeUndefined();
- });
- });
- describe('#widgetExtensions()', () => {
- it('should get the registered extensions for a given widget', () => {
- const foo = new WidgetExtension();
- const bar = new WidgetExtension();
- registry.addWidgetExtension('fizz', foo);
- registry.addWidgetExtension('fizz', bar);
- registry.addWidgetExtension('buzz', foo);
- const fizz = toArray(registry.widgetExtensions('fizz'));
- expect(fizz[0]).toBe(foo);
- expect(fizz[1]).toBe(bar);
- expect(fizz.length).toBe(2);
- const buzz = toArray(registry.widgetExtensions('buzz'));
- expect(buzz[0]).toBe(foo);
- expect(toArray(buzz).length).toBe(1);
- expect(registry.widgetExtensions('baz').next()).toBeUndefined();
- });
- });
- describe('#getFileTypeForModel()', () => {
- beforeEach(() => {
- DocumentRegistry.getDefaultFileTypes().forEach(ft => {
- registry.addFileType(ft);
- });
- });
- it('should handle a directory', () => {
- const ft = registry.getFileTypeForModel({
- type: 'directory'
- });
- expect(ft.name).toBe('directory');
- });
- it('should handle a notebook', () => {
- const ft = registry.getFileTypeForModel({
- type: 'notebook'
- });
- expect(ft.name).toBe('notebook');
- });
- it('should handle a python file', () => {
- const ft = registry.getFileTypeForModel({
- name: 'foo.py'
- });
- expect(ft.name).toBe('python');
- });
- it('should handle an unknown file', () => {
- const ft = registry.getFileTypeForModel({
- name: 'foo.bar'
- });
- expect(ft.name).toBe('text');
- });
- it('should get the most specific extension', () => {
- [
- { name: 'json', extensions: ['.json'] },
- { name: 'vega', extensions: ['.vg.json'] }
- ].forEach(ft => {
- registry.addFileType(ft);
- });
- const ft = registry.getFileTypeForModel({
- name: 'foo.vg.json'
- });
- expect(ft.name).toBe('vega');
- });
- it('should be case insensitive', () => {
- const ft = registry.getFileTypeForModel({
- name: 'foo.PY'
- });
- expect(ft.name).toBe('python');
- });
- });
- describe('#getFileTypesForPath()', () => {
- beforeEach(() => {
- DocumentRegistry.getDefaultFileTypes().forEach(ft => {
- registry.addFileType(ft);
- });
- });
- it('should handle a notebook', () => {
- const ft = registry.getFileTypesForPath('foo/bar/baz.ipynb');
- expect(ft[0].name).toBe('notebook');
- });
- it('should handle a python file', () => {
- const ft = registry.getFileTypesForPath('foo/bar/baz.py');
- expect(ft[0].name).toBe('python');
- });
- it('should return an empty list for an unknown file', () => {
- const ft = registry.getFileTypesForPath('foo/bar/baz.weird');
- expect(ft.length).toBe(0);
- });
- it('should get the most specific extension first', () => {
- [
- { name: 'json', extensions: ['.json'] },
- { name: 'vega', extensions: ['.vg.json'] }
- ].forEach(ft => {
- registry.addFileType(ft);
- });
- const ft = registry.getFileTypesForPath('foo/bar/baz.vg.json');
- expect(ft[0].name).toBe('vega');
- expect(ft[1].name).toBe('json');
- });
- it.each([
- ['python', null, 'foo/bar/baz.PY'],
- ['r-markdown', ['.Rmd'], 'foo/bar/baz.Rmd']
- ])('should be case insensitive', (name, extensions, filename) => {
- if (extensions) {
- registry.addFileType({ name, extensions });
- }
- const ft = registry.getFileTypesForPath(filename);
- expect(ft[0].name).toBe(name);
- });
- it('should support pattern matching', () => {
- registry.addFileType({
- name: 'test',
- extensions: ['.temp'],
- pattern: '.*\\.test$'
- });
- const ft = registry.getFileTypesForPath('foo/bar/baz.test');
- expect(ft[0].name).toBe('test');
- const ft2 = registry.getFileTypesForPath('foo/bar/baz.temp');
- expect(ft2[0].name).toBe('test');
- });
- });
- });
- });
|