diff --git a/app/lib/file-context/__tests__/file-context-spec.js b/app/lib/file-context/__tests__/file-context-spec.js index 34189e891..2674704ab 100644 --- a/app/lib/file-context/__tests__/file-context-spec.js +++ b/app/lib/file-context/__tests__/file-context-spec.js @@ -63,7 +63,9 @@ describe('FileContext', function() { // when await waitFor(() => { - fileContext.addFile(filePath, 'foo'); + fileContext.addFile(filePath, { + localValue: 'foo' + }); }); // then @@ -76,6 +78,28 @@ describe('FileContext', function() { }); + it('adding file with explicit processor', async function() { + + // given + const filePath = path.resolve(__dirname, './fixtures/extensions/bpmn.unrecognized'); + + // when + await waitFor(() => { + fileContext.addFile(filePath, { + processor: 'bpmn' + }); + }); + + // then + expectItems(fileContext, [ + { + uri: toFileUrl(path.resolve(__dirname, './fixtures/extensions/bpmn.unrecognized')), + processor: 'bpmn' + } + ]); + }); + + it('removing file', async function() { // given @@ -158,35 +182,35 @@ describe('FileContext', function() { }); - it('should NOT throw for unrecognized extension', async function() { + describe('error handling', function() { - // given - const filePath = path.resolve(__dirname, './fixtures/extensions/bpmn.unrecognized'); + it('should NOT throw for unrecognized extension', async function() { - // when - const file = await fileContext.addFile(filePath); + // given + const filePath = path.resolve(__dirname, './fixtures/extensions/bpmn.unrecognized'); - // then - expect(file).to.exist; - expect(file.metadata).to.have.property('type'); - }); + // when + const file = await fileContext.addFile(filePath); + // then + expect(file).to.exist; + expect(file.metadata).to.have.property('type'); + }); - it('should NOT throw for missing extension', async function() { - // given - const filePath = path.resolve(__dirname, './fixtures/extensions/no-extension'); + it('should NOT throw for no extension', async function() { - // when - const file = await fileContext.addFile(filePath); + // given + const filePath = path.resolve(__dirname, './fixtures/extensions/no-extension'); - // then - expect(file).to.exist; - expect(file.metadata).to.have.property('type'); - }); + // when + const file = await fileContext.addFile(filePath); + // then + expect(file).to.exist; + expect(file.metadata).to.have.property('type'); + }); - describe('broken files', function() { it('should NOT throw for empty BPMN', async function() { diff --git a/app/lib/file-context/file-context.js b/app/lib/file-context/file-context.js index 6501ef44c..edc03a569 100644 --- a/app/lib/file-context/file-context.js +++ b/app/lib/file-context/file-context.js @@ -79,25 +79,20 @@ module.exports = class FileContext extends EventEmitter { * Add file. * * @param { string } uri - * @param { string } [localValue] - */ - addFile(uri, localValue) { - return this._indexer.add(toFileUrl(uri), localValue); - } - - /** - * Update file. + * @param { { localValue?: string, processor?: string } } [options] * - * @param { string } uri + * @returns { Promise } */ - updateFile(uri) { - return this.addFile(toFileUrl(uri)); + addFile(uri, options) { + return this._indexer.add(toFileUrl(uri), options); } /** * Remove file. * * @param { string } uri + * + * @returns { undefined } */ removeFile(uri) { return this._indexer.remove(toFileUrl(uri)); @@ -106,19 +101,24 @@ module.exports = class FileContext extends EventEmitter { /** * Handle file opened. * - * @param { { uri: string, value: string } } fileProps + * @param { string } uri + * @param { { processor?: string } } + * + * @returns { Promise } */ - fileOpened(fileProps) { - return this._indexer.fileOpened(fileProps); + fileOpened(uri, options) { + return this._indexer.fileOpened(uri, options); } /** * Handle file content changed. * - * @param { { uri: string, value: string } } fileProps + * @param { string } uri + * @param { string } value + * @param { { processor?: string } } [options] */ - fileContentChanged(fileProps) { - return this._indexer.fileContentChanged(fileProps); + fileContentChanged(uri, value, options) { + return this._indexer.fileContentChanged(uri, value, options); } /** diff --git a/app/lib/file-context/indexer.js b/app/lib/file-context/indexer.js index 64382dae7..bca281db3 100644 --- a/app/lib/file-context/indexer.js +++ b/app/lib/file-context/indexer.js @@ -96,17 +96,24 @@ module.exports = class Indexer { /** * @param { string } uri - * @param { string } [localValue] + * @param { { localValue?: string, processor?: string } } [options] + * + * @returns { Promise } */ - add(uri, localValue) { + add(uri, options = {}) { uri = toFileUrl(uri); - this._logger.info('indexer:add', uri, localValue); + const { + localValue, + processor + } = options; + + this._logger.info('indexer:add', uri, localValue, processor); let indexItem = this.items.get(uri); if (!indexItem) { - indexItem = createIndexItem({ uri, localValue }); + indexItem = createIndexItem({ uri, localValue, processor }); this.items.set(uri, indexItem); } @@ -126,35 +133,30 @@ module.exports = class Indexer { /** * Notify file opened * - * @param { { uri: string, value: string } } fileProps + * @param { string } uri + * @param { { processor?: string } } [options] + * + * @returns { Promise } */ - fileOpened(fileProps) { - - const { - uri, - value - } = fileProps; - + fileOpened(uri, options = {}) { this._emit('file-opened', uri); - return this.add(toFileUrl(uri), value); + return this.add(toFileUrl(uri), options); } /** * Notify file content changed * - * @param { { uri: string, value: string } } fileProps + * @param { string } uri + * @param { string } value + * @param { { processor?: string } } [options] + * + * @returns { Promise } */ - fileContentChanged(fileProps) { - - const { - uri, - value - } = fileProps; - + fileContentChanged(uri, value, options = {}) { this._emit('file-content-changed', uri); - return this.add(toFileUrl(uri), value); + return this.add(toFileUrl(uri), value, options); } /** @@ -345,7 +347,8 @@ module.exports = class Indexer { /** * @param { { * uri: string, - * localValue?: string + * localValue?: string, + * processor?: string * } } item * * @return {IndexItem} @@ -355,6 +358,7 @@ function createIndexItem(item) { const { uri, localValue, + processor, ...rest } = item; @@ -373,7 +377,8 @@ function createIndexItem(item) { this.localValue = value; }, file, - localValue + localValue, + processor }; } \ No newline at end of file diff --git a/app/lib/file-context/processor.js b/app/lib/file-context/processor.js index d9867c704..49d6fa34e 100644 --- a/app/lib/file-context/processor.js +++ b/app/lib/file-context/processor.js @@ -38,6 +38,16 @@ module.exports = class Processor { process(item) { this._logger.info('processor:process', item.uri); + if (item.processor) { + const processor = this._processors.find(processor => processor.id === item.processor); + + if (processor) { + return processor.process(item); + } + + this._logger.warn('processor:process', `Processor with id ${ item.processor } not found`); + } + const processor = this._processors.find(processor => processor.extensions.includes(getFileExtension(item.file.path))); if (!processor) { diff --git a/app/lib/file-context/processors/bpmnProcessor.js b/app/lib/file-context/processors/bpmnProcessor.js index 60c8ca5b2..2b4a1a64a 100644 --- a/app/lib/file-context/processors/bpmnProcessor.js +++ b/app/lib/file-context/processors/bpmnProcessor.js @@ -21,7 +21,8 @@ const { } = require('./util'); module.exports = { - extensions: [ '.bpmn', '.xml' ], + id: 'bpmn', + extensions: [ '.bpmn' ], process: async (item) => { let rootElement, ids, linkedIds; diff --git a/app/lib/file-context/processors/dmnProcessor.js b/app/lib/file-context/processors/dmnProcessor.js index 980e7305a..bea1fdc8c 100644 --- a/app/lib/file-context/processors/dmnProcessor.js +++ b/app/lib/file-context/processors/dmnProcessor.js @@ -18,6 +18,7 @@ const { } = require('./util'); module.exports = { + id: 'dmn', extensions: [ '.dmn' ], process: async (item) => { let rootElement, ids; diff --git a/app/lib/file-context/processors/formProcessor.js b/app/lib/file-context/processors/formProcessor.js index 9a5155ba6..9a4605839 100644 --- a/app/lib/file-context/processors/formProcessor.js +++ b/app/lib/file-context/processors/formProcessor.js @@ -11,6 +11,7 @@ const assert = require('node:assert'); module.exports = { + id: 'form', extensions: [ '.form' ], process: async (item) => { let formId; diff --git a/app/lib/file-context/processors/processApplicationProcessor.js b/app/lib/file-context/processors/processApplicationProcessor.js index a1a73c180..4059fc32e 100644 --- a/app/lib/file-context/processors/processApplicationProcessor.js +++ b/app/lib/file-context/processors/processApplicationProcessor.js @@ -9,6 +9,7 @@ */ module.exports = { + id: 'processApplication', extensions: [ '.process-application' ], process: async (item) => { return { diff --git a/app/lib/file-context/types.d.ts b/app/lib/file-context/types.d.ts index ca34f9353..97f6ec28b 100644 --- a/app/lib/file-context/types.d.ts +++ b/app/lib/file-context/types.d.ts @@ -22,6 +22,7 @@ export type IndexItem = { file: File, localValue?: any, metadata: Metadata, + processor?: string, uri: string, value: any, [key: string]: any diff --git a/app/lib/index.js b/app/lib/index.js index ad01f0b17..655bbfdbf 100644 --- a/app/lib/index.js +++ b/app/lib/index.js @@ -224,26 +224,30 @@ renderer.on('system-clipboard:write-text', function(options, done) { }); // file context ////////// -renderer.on('file-context:add-root', function(filePath, done) { +renderer.on('file-context:add-root', function(options, done) { + const { filePath } = options; + fileContext.addRoot(filePath); done(null); }); -renderer.on('file-context:remove-root', function(filePath, done) { +renderer.on('file-context:remove-root', function(options, done) { + const { filePath } = options; + fileContext.removeRoot(filePath); done(null); }); -renderer.on('file-context:file-opened', function(filePath, value, done) { - fileContext.fileOpened({ uri: toFileUrl(filePath), value }); +renderer.on('file-context:file-opened', function(filePath, options, done) { + fileContext.fileOpened(toFileUrl(filePath), options); done(null); }); -renderer.on('file-context:file-content-changed', function(filePath, value, done) { - fileContext.fileContentChanged({ uri: toFileUrl(filePath), value }); +renderer.on('file-context:file-content-changed', function(filePath, value, options, done) { + fileContext.fileContentChanged(toFileUrl(filePath), value, options); done(null); }); @@ -254,15 +258,6 @@ renderer.on('file-context:file-closed', function(filePath, done) { done(null); }); -renderer.on('file:content-changed', function(filePath, contents, done) { - fileContext.fileContentChanged({ - uri: toFileUrl(filePath), - value: contents - }); - - done(null); -}); - // filesystem ////////// renderer.on('file:read', function(filePath, options = {}, done) { diff --git a/client/src/app/App.js b/client/src/app/App.js index a2a4c2df1..dba5366b7 100644 --- a/client/src/app/App.js +++ b/client/src/app/App.js @@ -2109,18 +2109,34 @@ export class App extends PureComponent { _onTabOpened(tab) { if (!this.isUnsaved(tab)) { - this.getGlobal('backend').send('file-context:file-opened', tab.file.path, undefined); + const { + file, + type + } = tab; + + this.getGlobal('backend').send('file-context:file-opened', file.path, { + processor: getProcessor(type) + }); } } _onTabClosed(tab) { if (!this.isUnsaved(tab)) { - this.getGlobal('backend').send('file-context:file-closed', tab.file.path); + const { file } = tab; + + this.getGlobal('backend').send('file-context:file-closed', file.path); } } _onTabSaved(tab) { - this.getGlobal('backend').send('file-context:file-content-changed', tab.file.path, undefined); + const { + file, + type + } = tab; + + this.getGlobal('backend').send('file-context:file-content-changed', file.path, file.contents, { + processor: getProcessor(type) + }); } render() { @@ -2537,3 +2553,19 @@ function failSafe(fn, errorHandler) { } }; } + +function getProcessor(type) { + if (type === 'cloud-bpmn') { + return 'bpmn'; + } + + if (type === 'cloud-dmn') { + return 'dmn'; + } + + if (type === 'cloud-form') { + return 'form'; + } + + return null; +} \ No newline at end of file diff --git a/client/src/app/__tests__/AppSpec.js b/client/src/app/__tests__/AppSpec.js index 8e881aca8..e67d1a434 100644 --- a/client/src/app/__tests__/AppSpec.js +++ b/client/src/app/__tests__/AppSpec.js @@ -382,12 +382,15 @@ describe('', function() { }); // when - const file1 = createFile('1.bpmn'); + const file1 = createFile('1.cloud-bpmn'); await app.openFiles([ file1 ]); // then - expect(sendSpy).to.have.been.calledWith('file-context:file-opened', file1.path, undefined); + expect(sendSpy).to.have.been.calledWith('file-context:file-opened', { + filePath: file1.path, + processor: 'bpmn' + }); }); @@ -407,7 +410,7 @@ describe('', function() { }); // when - await app.createDiagram('bpmn'); + await app.createDiagram('cloud-bpmn'); // then expect(sendSpy).not.to.have.been.calledWith('file-context:file-opened'); @@ -430,14 +433,16 @@ describe('', function() { }); // when - const file1 = createFile('1.bpmn'); + const file1 = createFile('1.cloud-bpmn'); const [ tab ] = await app.openFiles([ file1 ]); await app.closeTab(tab); // then - expect(sendSpy).to.have.been.calledWith('file-context:file-closed', file1.path); + expect(sendSpy).to.have.been.calledWith('file-context:file-closed', { + filePath: file1.path + }); }); @@ -457,7 +462,7 @@ describe('', function() { }); // when - const tab = await app.createDiagram('bpmn'); + const tab = await app.createDiagram('cloud-bpmn'); await app.closeTab(tab); @@ -485,7 +490,7 @@ describe('', function() { }); // when - const file1 = createFile('1.bpmn'); + const file1 = createFile('1.cloud-bpmn'); fileSystem.setWriteFileResponse(0, Promise.resolve({ ...file1 @@ -496,7 +501,10 @@ describe('', function() { await app.triggerAction('save'); // then - expect(sendSpy).to.have.been.calledWith('file-context:file-content-changed', file1.path, undefined); + expect(sendSpy).to.have.been.calledWith('file-context:file-content-changed', { + filePath: file1.path, + processor: 'bpmn' + }); }); }); @@ -1176,7 +1184,7 @@ describe('', function() { it('should save tab with correct extension', async function() { // given - const file = createFile('diagram_1.bpmn', { type: 'cloud-bpmn' }); + const file = createFile('diagram_1.bpmn'); await app.openFiles([ file ]); @@ -3452,8 +3460,7 @@ describe('', function() { const openedTabs = await app.openFiles([ createFile('1.form', { - contents: 'foo', - type: 'form' + contents: 'foo' }) ]); @@ -3477,8 +3484,7 @@ describe('', function() { const openedTabs = await app.openFiles([ createFile('1.form', { - contents: 'linting-errors', - type: 'form' + contents: 'linting-errors' }) ]); @@ -3510,8 +3516,7 @@ describe('', function() { const openedTabs = await app.openFiles([ createFile('1.form', { - contents, - type: 'form' + contents }) ]); @@ -3557,8 +3562,7 @@ describe('', function() { const openedTabs = await app.openFiles([ createFile('1.form', { - contents: 'foo', - type: 'form' + contents: 'foo' }) ]); @@ -3582,8 +3586,7 @@ describe('', function() { await app.openFiles([ createFile('1.form', { - contents: 'linting-errors', - type: 'form' + contents: 'linting-errors' }) ]); @@ -3854,16 +3857,14 @@ function createFile(name, options = {}) { const { contents = 'foo', lastModified, - path = name, - type = 'bpmn' + path = name } = options; return { contents, lastModified, name, - path, - type + path }; }