From 138ce432e208e1c17120c3a1eb5c76018beffc0e Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 8 Aug 2024 14:15:56 -0700 Subject: [PATCH 01/29] Initial commit of template files From https://github.com/open-ephys/onix1-bonsai-docs/commit/c2e0bd45dd2f89a8e8f79c7a125486c10cf10ef3 Co-authored-by: Cris Co-authored-by: Brandon Parks --- template/api/ManagedReference.extension.js | 622 ++++++++++++++++++ .../api/ManagedReference.html.primary.tmpl | 7 + template/api/ManagedReference.overwrite.js | 5 + template/api/conceptual.html.primary.tmpl | 40 ++ template/api/partials/class.tmpl.partial | 109 +++ template/api/partials/diagram.tmpl.partial | 114 ++++ template/api/partials/enum.tmpl.partial | 38 ++ .../api/partials/propertyTables.tmpl.partial | 37 ++ template/api/toc.extension.js | 74 +++ 9 files changed, 1046 insertions(+) create mode 100644 template/api/ManagedReference.extension.js create mode 100644 template/api/ManagedReference.html.primary.tmpl create mode 100644 template/api/ManagedReference.overwrite.js create mode 100644 template/api/conceptual.html.primary.tmpl create mode 100644 template/api/partials/class.tmpl.partial create mode 100644 template/api/partials/diagram.tmpl.partial create mode 100644 template/api/partials/enum.tmpl.partial create mode 100644 template/api/partials/propertyTables.tmpl.partial create mode 100644 template/api/toc.extension.js diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js new file mode 100644 index 0000000..c5516c8 --- /dev/null +++ b/template/api/ManagedReference.extension.js @@ -0,0 +1,622 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +function removeBottomMargin(str){ + return str.split('').reverse().join('') + .replace( ' o --> output diagrams +function defineInputsAndOutputs(model){ + operators = []; + if (model.oe.hubOrDevice === 'hub'){ + const hubChildrenLength = model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children.length; + for (let i = 0; i < hubChildrenLength; i++){ + if (model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].name[0].value.includes('Process')){ + description = [ + model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].summary, + model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].remarks + ].join(''); + } + input = {}; + if (model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters && model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0]){ + input = { + 'specName': replaceIObservableAndTSource(model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0].type.specName[0].value), + 'name': model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0].type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), + 'description': removeBottomMargin([ model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0].description, + model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0].remarks].join(''))}; + input.internal = true; + } + output = {}; + dataFrame = []; + if (model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return){ + output = { + 'specName': replaceIObservableAndTSource(model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.type.specName[0].value), + 'name': model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), + 'description': removeBottomMargin([ model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.description, + model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.remarks].join(''))}; + output.internal = true; + outputYml = [ '~/api/', + model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.type.uid.replaceAll(/(\D*{)|(}$)/g, ''), + '.yml'].join(''); + if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['children'] && (model['__global']['_shared'][outputYml].type === 'class')){ + output.dataFrameDescription = [ + model['__global']['_shared'][outputYml].summary, + model['__global']['_shared'][outputYml].remarks].join(''); + const outputYmlChildrenLength = model['__global']['_shared'][outputYml]['children'].length; + for (let j = 0; j < outputYmlChildrenLength; j++){ + if (model['__global']['_shared'][outputYml]['children'][j].type === 'property'){ + potentialEnumYml = '~/api/' + model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.uid + '.yml'; + let enumFields = []; + if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ + enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); + } + if (enumFields.length > 0){ + output.dataFrameDescription = [ + model['__global']['_shared'][outputYml].summary, + model['__global']['_shared'][outputYml].remarks].join(''), + dataFrame.push({ + 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([ model['__global']['_shared'][outputYml]['children'][j].summary, + model['__global']['_shared'][outputYml]['children'][j].remarks].join('')), + 'enumFields': enumFields, + 'hasEnum': true + }); + } + else{ + dataFrame.push({ + 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([ model['__global']['_shared'][outputYml]['children'][j].summary, + model['__global']['_shared'][outputYml]['children'][j].remarks].join('')) + }); + } + } + } + } + } + } + if (Object.keys(input).length && Object.keys(dataFrame).length){ + operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasInput': true, 'hasDataFrame': true}); + } + else if (Object.keys(input).length){ + operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasInput': true}); + } + else if (Object.keys(dataFrame).length){ + operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasDataFrame': true}); + } + else{ + operators.push({'description': description, 'output': output}); + } + } + else if (model.children){ + const childrenLength = model.children.length; + for (let i = 0; i < childrenLength; i++){ + if (model.children[i].uid.includes('Generate') || model.children[i].uid.includes('Process')){ + description = [model.children[i].summary, model.children[i].remarks].join(''); + input = {}; + if (model.children[i].syntax.parameters && model.children[i].syntax.parameters[0]){ + input = { + 'specName': replaceIObservableAndTSource(model.children[i].syntax.parameters[0].type.specName[0].value), + 'name': model.children[i].syntax.parameters[0].type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), + 'description': removeBottomMargin([model.children[i].syntax.parameters[0].description, model.children[i].syntax.parameters[0].remarks].join('')) + }; + input.dataFrame = []; + if (model.__global._shared['~/api/OpenEphys.Onix1.' + input.name + '.yml']){ + input.internal = true; + inputYml = [ '~/api/', + model.children[i].syntax.parameters[0].type.uid.replaceAll(/(\D*{)|(}$)/g, ''), + '.yml'].join(''); + if (model['__global']['_shared'][inputYml] && model['__global']['_shared'][inputYml]['children'] && (model['__global']['_shared'][inputYml].type === 'class')){ + input.dataFrameDescription = [ + model['__global']['_shared'][inputYml].summary, + model['__global']['_shared'][inputYml].remarks + ].join(''); + const inputYmlChildrenLength = model['__global']['_shared'][inputYml]['children'].length; + for (let j = 0; j < inputYmlChildrenLength; j++){ + if (model['__global']['_shared'][inputYml]['children'][j] && model['__global']['_shared'][inputYml]['children'][j].type === 'property'){ + let enumFields = []; + if (model['__global']['_shared'][inputYml]['children'][j].syntax.parameters[0]){ + potentialEnumYml = '~/api/' + model['__global']['_shared'][inputYml]['children'][j].syntax.parameters[0].type.uid + '.yml'; + if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ + enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); + } + } + if (enumFields.length > 0){ + input.dataFrame.push({ + 'name': model['__global']['_shared'][inputYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][inputYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([ model['__global']['_shared'][inputYml]['children'][j].summary, + model['__global']['_shared'][inputYml]['children'][j].remarks].join('')), + 'enumFields': enumFields, + 'hasEnum': true + }); + } + else{ + input.dataFrame.push({ + 'name': model['__global']['_shared'][inputYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][inputYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([ model['__global']['_shared'][inputYml]['children'][j].summary, + model['__global']['_shared'][inputYml]['children'][j].remarks].join('')) + }); + } + } + } + } + else if (model['__global']['_shared'][inputYml] && model['__global']['_shared'][inputYml]['children'] && (model['__global']['_shared'][inputYml].type === 'enum')){ + input.internal = true; + input.dataFrameDescription = [ + model['__global']['_shared'][inputYml].summary, + model['__global']['_shared'][inputYml].remarks + ].join(''); + const inputYmlChildrenLength = model['__global']['_shared'][inputYml]['children'].length; + for (let j = 0; j < inputYmlChildrenLength; j++){ + if (model['__global']['_shared'][inputYml]['children'][j].type === 'property'){ + potentialEnumYml = '~/api/' + model['__global']['_shared'][inputYml]['children'][j].syntax.parameters[0].type.uid + '.yml'; + let enumFields = []; + if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ + enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); + } + if (enumFields.length > 0){ + dataFrame.push({ + 'name': model['__global']['_shared'][inputYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][inputYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([ model['__global']['_shared'][inputYml]['children'][j].summary, + model['__global']['_shared'][inputYml]['children'][j].remarks].join('')), + 'enumFields': enumFields, + 'hasEnum': true + }); + } + else{ + dataFrame.push({ + 'name': model['__global']['_shared'][inputYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][inputYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([ model['__global']['_shared'][inputYml]['children'][j].summary, + model['__global']['_shared'][inputYml]['children'][j].remarks].join('')) + }); + } + } + } + } + } + else { + input.external = true; + } + } + if (model.children[i].syntax.return){ + output = { + 'specName': replaceIObservableAndTSource(model.children[i].syntax.return.type.specName[0].value), + 'name': model.children[i].syntax.return.type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), + 'description': removeBottomMargin([model.children[i].syntax.return.description, model.children[i].syntax.return.remarks].join(''))}; + dataFrame = []; + outputYml = [ '~/api/', + model.children[i].syntax.return.type.uid.replaceAll(/(\D*{)|(}$)/g, ''), + '.yml'].join(''); + if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['children'] && (model['__global']['_shared'][outputYml].type === 'class')){ + output.internal = true; + output.dataFrameDescription = [ + model['__global']['_shared'][outputYml].summary, + model['__global']['_shared'][outputYml].remarks].join(''); + const outputYmlChildrenLength = model['__global']['_shared'][outputYml]['children'].length; + for (let j = 0; j < outputYmlChildrenLength; j++){ + if (model['__global']['_shared'][outputYml]['children'][j].type === 'property'){ + potentialEnumYml = '~/api/' + model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.uid + '.yml'; + let enumFields = []; + if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ + enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); + } + if (enumFields.length > 0){ + dataFrame.push({ + 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([ model['__global']['_shared'][outputYml]['children'][j].summary, + model['__global']['_shared'][outputYml]['children'][j].remarks].join('')), + 'enumFields': enumFields, + 'hasEnum': true + }); + } + else{ + dataFrame.push({ + 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([ model['__global']['_shared'][outputYml]['children'][j].summary, + model['__global']['_shared'][outputYml]['children'][j].remarks].join('')) + }); + } + } + } + } + if (dataFrame.length === 0 && input.dataFrame && input.dataFrame.length > 0){ + dataFrame = input.dataFrame; + output.useInputDataFrame = true;; + } + else if (!output.internal) { + output.external = true; + } + if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['inheritedMembers']){ + output.internal = true; + output.external = false; + const inheritedMembersLength = model['__global']['_shared'][outputYml]['inheritedMembers'].length; + for (let j = 0; j < inheritedMembersLength; j++){ + if (model['__global']['_shared'][outputYml]['inheritedMembers'][j].type === 'property'){ + let inheritedMemberYml = '~/api/' + model['__global']['_shared'][outputYml]['inheritedMembers'][j].parent + '.yml'; + if (model['__global']['_shared'][inheritedMemberYml]['children']){ + let inheritedMemberChildrenLength = model['__global']['_shared'][inheritedMemberYml]['children'].length; + for (let k = 0; k < inheritedMemberChildrenLength; k++){ + if (model['__global']['_shared'][outputYml]['inheritedMembers'][j].uid === model['__global']['_shared'][inheritedMemberYml]['children'][k].uid){ + dataFrame.push({ + 'name': model['__global']['_shared'][outputYml]['inheritedMembers'][j].name[0].value, + 'type': model['__global']['_shared'][inheritedMemberYml]['children'][k].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([model['__global']['_shared'][inheritedMemberYml]['children'][k].summary, + model['__global']['_shared'][inheritedMemberYml]['children'][k].remarks].join('')) + }); + } + } + } + } + } + } + else if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['children'] && (model['__global']['_shared'][outputYml].type === 'enum')){ + output.internal = true; + output.external = false; + output.dataFrameDescription = [ + model['__global']['_shared'][outputYml].summary, + model['__global']['_shared'][outputYml].remarks + ].join(''); + output.enumFields = defineEnumFields(model['__global']['_shared'][outputYml]); + output.isEnum = true; + } + else if (!output.internal){ + output.external = true; + } + } + if (Object.keys(input).length && Object.keys(dataFrame).length){ + operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasInput': true, 'hasDataFrame': true}); + } + else if (Object.keys(input).length){ + operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasInput': true}); + } + else if (Object.keys(dataFrame).length){ + operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasDataFrame': true}); + } + else { + operators.push({'description': description, 'output': output}); + } + } + } + } + return operators; +} + +// Define source or sink in documentation by checking for an explicit Category tag. If the class does not provide one, +// check the inheritance tree of the class. If the class inherits Bonsai.Sink and Bonsai.Combinator, ignore the Bonsai.Sink +// inheritance overrides the Bonsai.Combinator inheritance for determining whether an operator is a source or a combinator. This +// is because maybe sink operators inherit Bonsai.Combinator in addition to Bonsai.Sink. +function defineOperatorType(model){ + let operatorType = {'source': false, 'sink': false, 'combinator': false}; + if (model.syntax && model.syntax.content[0].value){ + if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Source)]')){ + operatorType.source = true; + } + else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Sink)]')){ + operatorType.sink = true; + } + else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Combinator)]')){ + operatorType.combinator = true; + } + } + if (!(operatorType.source || operatorType.sink || operatorType.combinator)){ + if (model.inheritance){ + const inheritanceLength = model.inheritance.length; + for (let i = 0; i < inheritanceLength; i++){ + if (model.inheritance[i].uid.includes('Bonsai.Source')){ + operatorType.source = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.Sink')){ + operatorType.sink = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.Combinator')){ + operatorType.combinator = true; + } + if (model.inheritance[i].uid.includes('OpenEphys.Onix1.MultiDeviceFactory')){ + operatorType.hub = true; + } + else if (model.inheritance[i].uid.includes('OpenEphys.Onix1.SingleDeviceFactory')){ + operatorType.device = true; + } + } + } + } + operatorType.showWorkflow = operatorType.source | operatorType.sink | operatorType.combinator; + return operatorType; +} + +function defineSubOperators(model){ + let subOperators = [] + if (model.children){ + const childrenLength = model.children.length; + for (let i = 0; i < childrenLength; i++){ + if (model.children[i].type === 'property'){ + potentialSubOperatorYml = '~/api/' + model.children[i].syntax.return.type.uid + '.yml'; + if (model['__global']['_shared'][potentialSubOperatorYml]){ + subOperatorChildrenLength = model['__global']['_shared'][potentialSubOperatorYml]['children'].length; + let subProperties = []; + for (let j = 0; j < subOperatorChildrenLength; j++){ + if (model['__global']['_shared'][potentialSubOperatorYml]['children'][j].type === 'property'){ + let enumFields = []; + potentialEnumYml = '~/api/' + model['__global']['_shared'][potentialSubOperatorYml]['children'][j].syntax.return.type.uid + '.yml'; + if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ + enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); + } + if (enumFields.length > 0){ + subProperties.push({'name': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin( [model['__global']['_shared'][potentialSubOperatorYml]['children'][j].summary, + model['__global']['_shared'][potentialSubOperatorYml]['children'][j].remarks].join('')), + 'enumFields': enumFields, + 'hasEnum': true}); + } + else{ + subProperties.push({'name': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].name[0].value, + 'type': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin( [model['__global']['_shared'][potentialSubOperatorYml]['children'][j].summary, + model['__global']['_shared'][potentialSubOperatorYml]['children'][j].remarks].join('')) + }); + } + } + } + if (subProperties.length > 0){ + subOperators.push({ + 'object': model.children[i].name[0].value, + 'type': model.children[i].syntax.return.type.specName[0].value, + 'subProperties': subProperties, + 'hasSubProperties': true, + 'subOperator': true + }); + } + else if (model.__global._shared['~/api/' + model.children[i].name[0].value + '.yml']){ + subOperators.push({ + 'object': model.children[i].name[0].value, + 'type': model.children[i].syntax.return.type.specName[0].value, + 'subOperator': true + }); + } + } + } + } + } + return subOperators +} + +// compile list of properties +function defineProperties(model){ + properties = []; + if (model.children){ + const childrenLength = model.children.length; + for (let i = 0; i < childrenLength; i++){ + if (model.children[i].type === 'property'){ + potentialEnumYml = '~/api/' + model['children'][i].syntax.return.type.uid + '.yml'; + let enumFields = []; + if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ + enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); + } + if (enumFields.length > 0){ + properties.push({ + 'name': model.children[i].name[0].value, + 'type': model.children[i].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([model.children[i].summary, model.children[i].remarks].join('')), + 'enumFields': enumFields, + 'hasEnum': true + }); + } + else { + properties.push({ + 'name': model.children[i].name[0].value, + 'type': model.children[i].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([model.children[i].summary, model.children[i].remarks].join('')) + }); + } + } + } + } + if (model.inheritedMembers){ + const inheritedMembersLength = model.inheritedMembers.length; + for (let i = 0; i < inheritedMembersLength; i++){ + if (model.inheritedMembers[i].type && (model.inheritedMembers[i].type === 'property')){ + let inheritedMemberYml = '~/api/' + model.inheritedMembers[i].parent + '.yml'; + if (model['__global']['_shared'][inheritedMemberYml]['children']){ + let inheritedMemberChildrenLength = model['__global']['_shared'][inheritedMemberYml]['children'].length; + for (let j = 0; j < inheritedMemberChildrenLength; j++){ + if (model.inheritedMembers[i].uid === model['__global']['_shared'][inheritedMemberYml]['children'][j].uid){ + properties.push( + {'name': model.inheritedMembers[i].name[0].value, + 'type': model['__global']['_shared'][inheritedMemberYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([model['__global']['_shared'][inheritedMemberYml]['children'][j].summary, + model['__global']['_shared'][inheritedMemberYml]['children'][j].remarks].join('')) + }); + } + } + } + } + } + } + return properties; +} + +function sortProperties(properties){ + let propertyNames = []; + let propertyNamesThatFitPattern = []; + const propertiesLength = properties.length; + for (let i = 0; i < propertiesLength; i++){ + propertyNames.push([properties[i].name, + /\D+\d+$/.test(properties[i].name), + String(properties[i].name.match(/\D+/)), + Number(properties[i].name.match(/\d+$/))]); + } + for (let i = 0; i < propertiesLength; i++){ + if (propertyNames[i][1]){ + if (!propertyNamesThatFitPattern.includes(propertyNames[i][2])){ + propertyNamesThatFitPattern.push(propertyNames[i][2]); + } + } + } + const propertyNamesThatFitPatternLength = propertyNamesThatFitPattern.length; + for (let j = 0; j < propertyNamesThatFitPatternLength; j++){ + for (let i = 1; i < propertiesLength; i++){ + for (let k = i; k > 0; k--){ + if ((propertyNames[k][2] === propertyNamesThatFitPattern[j]) && (propertyNames[k - 1][2] === propertyNamesThatFitPattern[j])){ + if (propertyNames[k][3] < propertyNames[k - 1][3]){ + swapElements(properties, k, k - 1); + swapElements(propertyNames, k, k - 1); // why does this need to be here for this sortProperties function to work? + } + } + } + } + } + return properties; +} + +const swapElements = (array, index1, index2) => { + const temp = array[index1]; + array[index1] = array[index2]; + array[index2] = temp; +}; + +function defineEnumFields(model){ + let enumFields = []; + if (model.children){ + const childrenLength = model.children.length; + for (let i = 0; i < childrenLength; i++){ + if (model.children[i].type === 'field'){ + enumFields.push({ + 'field&value': model.children[i].syntax.content[0].value, + 'description': removeBottomMargin([ model.children[i].summary, + model.children[i].remarks].join('')) + }); + } + } + } + return enumFields; +} + + +/** + * This method will be called at the start of exports.transform in ManagedReference.html.primary.js + */ +exports.preTransform = function (model) { + + model.oe = {}; + + model.oe.description = [model.summary, model.remarks].join(''); + + operatorType = defineOperatorType(model); + if (operatorType.source){ + model.oe.operatorType = 'source'; + } + else if (operatorType.sink){ + model.oe.operatorType = 'sink'; + } + else if (operatorType.combinator){ + model.oe.operatorType = 'combinator'; + } + + if (operatorType.showWorkflow) { + model.showWorkflow = operatorType.showWorkflow; + } + else { + + } + + if (operatorType.device) { + model.oe.hubOrDevice = 'device'; + model.oe.device = true; + } + else if (operatorType.hub){ + model.oe.hubOrDevice = 'hub'; + model.oe.hub = true; + } + + operators = defineInputsAndOutputs(model); + if (operators.length > 0){ + model.oe.operators = operators; + } + + properties = defineProperties(model); + if (properties.length > 0){ + model.oe.hasProperties = true; + model.oe.properties = sortProperties(properties); + } + + subOperators = defineSubOperators(model); + if (subOperators.length > 0){ + model.oe.hasSubOperators = true; + model.oe.subOperators = subOperators; + } + + if (model.oe.hasProperties && model.oe.hasSubOperators){ + subPropertyNames = []; + hubProperties = []; + const subOperatorsLength = model.oe.subOperators.length; + for (let i = 0; i < subOperatorsLength; i++){ + subPropertyNames.push(model.oe.subOperators[i].object); + } + const propertiesLength = model.oe.properties.length; + for (let i = 0; i < propertiesLength; i++){ + const subPropertyNamesLength = subPropertyNames.length; + propertyNotInSubOperator = false; + for (let j = 0; j < subPropertyNamesLength; j++){ + if (model.oe.properties[i].name === subPropertyNames[j]){ + propertyNotInSubOperator = true; + } + } + if (!propertyNotInSubOperator){ + hubProperties.push(model.oe.properties[i]); + } + } + if (hubProperties.length > 0){ + model.oe.subOperators.push({ + 'object': 'Misc', + 'subProperties': hubProperties, + 'hasSubProperties': true, + 'subOperator': false + }) + } + } + + enumFields = defineEnumFields(model); + if (enumFields.length > 0){ + model.oe.hasEnumFields = true; + model.oe.enumFields = enumFields; + } + + if (model.uid.includes('DeviceFactory')){ + model.showWorkflow = false; + } + + return model; +} + +/** + * This method will be called at the end of exports.transform in ManagedReference.html.primary.js + */ +exports.postTransform = function (model) { + return model; +} diff --git a/template/api/ManagedReference.html.primary.tmpl b/template/api/ManagedReference.html.primary.tmpl new file mode 100644 index 0000000..5f4ab4f --- /dev/null +++ b/template/api/ManagedReference.html.primary.tmpl @@ -0,0 +1,7 @@ +{{!Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license.}} + +{{!master(layout/_master.tmpl)}} + +{{>partials/class}} + +{{>partials/enum}} \ No newline at end of file diff --git a/template/api/ManagedReference.overwrite.js b/template/api/ManagedReference.overwrite.js new file mode 100644 index 0000000..ff7ef9d --- /dev/null +++ b/template/api/ManagedReference.overwrite.js @@ -0,0 +1,5 @@ +exports.getOptions = function (model) { + return { + isShared: true + }; +} \ No newline at end of file diff --git a/template/api/conceptual.html.primary.tmpl b/template/api/conceptual.html.primary.tmpl new file mode 100644 index 0000000..921fadb --- /dev/null +++ b/template/api/conceptual.html.primary.tmpl @@ -0,0 +1,40 @@ +{{!master(layout/_master.tmpl)}} + +

{{title}}

+{{#isGuide}} +
+ +{{#workflow}} +{{#isDevice}} +{{>partials/device.workflow}} +{{/isDevice}} +{{#isHeadstage}} +{{>partials/headstage.workflow}} +
+{{>partials/headstage.devices}} +{{/isHeadstage}} +{{/workflow}} + +{{#visualize}} +
+

Visualize Data

+ +{{#visualize_timeseries}} +{{>partials/device.visualize_timeseries}} +{{/visualize_timeseries}} + +{{#visualize_mat}} +{{>partials/device.visualize_mat}} +{{/visualize_mat}} + +{{#visualize_text}} +{{>partials/device.visualize_text}} +{{/visualize_text}} + +

Refer to Visualizing Data for more information on visualizers and how to download them.

+

Note that data will not be shown until a workflow is running. Check out Running a Workflow to see how to run a workflow.

+ +{{/visualize}} +{{/isGuide}} + +{{{conceptual}}} \ No newline at end of file diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial new file mode 100644 index 0000000..0e25a93 --- /dev/null +++ b/template/api/partials/class.tmpl.partial @@ -0,0 +1,109 @@ +{{#isClass}} + +
+

+ {{name.0.value}} + {{#sourceurl}}{{/sourceurl}} +

+ {{#oe.operatorType}} +

+ {{oe.operatorType}} Operator +

+ {{/oe.operatorType}} +
+ +{{#oe.device}} + +
+ This operator is a device operator. If you are using Open Ephys hardware, use an aggregate operator that corresponds to your particular headstage(s) instead. Aggregate operators confer the following benefits: +
    +
  • The address properties of aggregate operators are automatically configured whereas a device operators requires manual configuration of its address property. This improves ease of using Open Ephys hardware.
  • +
  • All devices that belong to a hub (which is a collection of devices i.e. a headstage or breakout board) are automatically included, excluding the possibility of omitting configuration of a device that belongs to a hub. This improves ease of using Open Ephys hardware.
  • +
  • The workflow is less cluttered with configuration operators as one aggregate operator can correspond to multiple device operators. This improves workflow readability.
  • +
+
+ +{{/oe.device}} + +
{{{oe.description}}}
+ +{{#showWorkflow}} +

{{name.0.value}} Workflow

+{{/showWorkflow}} + +{{#oe.operatorType}} + +

Inputs & Outputs

+ +{{>partials/diagram}} + +{{/oe.operatorType}} + +{{#oe.hasSubOperators}} + +

Properties

+ +
{{name.0.value}} is a aggregate operator. It comprises of the following sub-operators:
+
+ +{{#oe.subOperators}} + +

{{{object}}}

+ +{{#subOperator}} +
{{{object}}} is a {{{type}}} operator encapsulated by the {{name.0.value}} operator.
+{{/subOperator}} + +{{#hasSubProperties}} + + + + + + + + + + {{#subProperties}} + {{>partials/propertyTables}} + {{/subProperties}} + +
PropertyTypeDescription
+ +{{/hasSubProperties}} + +{{^hasSubProperties}} + +
This subclass has no public properties.
+ +{{/hasSubProperties}} + +{{/oe.subOperators}} + +{{/oe.hasSubOperators}} + +{{^oe.hasSubOperators}} + +{{#oe.hasProperties}} + +

Properties

+ + + + + + + + + + {{#oe.properties}} + {{>partials/propertyTables}} + {{/oe.properties}} + +
PropertyTypeDescription
+ +{{/oe.hasProperties}} + +{{/oe.hasSubOperators}} + +{{/isClass}} \ No newline at end of file diff --git a/template/api/partials/diagram.tmpl.partial b/template/api/partials/diagram.tmpl.partial new file mode 100644 index 0000000..c87f104 --- /dev/null +++ b/template/api/partials/diagram.tmpl.partial @@ -0,0 +1,114 @@ +{{#oe.operators}} + +
{{{description}}}
+ + + + + + + + + + + + + + + + +
+ + + {{#input}} + + + {{/input}} + +
+ {{#internal}}
{{{name}}}
{{/internal}} + {{#external}}
{{{specName}}}
{{/external}} + {{{description}}} +
+ right-arrow +
+
+ representation of a source, sink, or combinator operator + + + + + + +
+ right-arrow + + {{#output.internal}}
{{{output.name}}}
{{/output.internal}} + {{#output.external}}
{{{output.specName}}}
{{/output.external}} +
{{{output.description}}}
+
+
+ +{{/oe.operators}} + +{{#oe.operators.0.hasDataFrame}} +{{^oe.operators.0.output.useInputDataFrame}} + +

{{{oe.operators.0.output.name}}}

+
{{{oe.operators.0.output.dataFrameDescription}}}
+ +{{/oe.operators.0.output.useInputDataFrame}} + +{{#oe.operators.0.output.useInputDataFrame}} + +

{{{oe.operators.0.input.name}}}

+
{{{oe.operators.0.input.dataFrameDescription}}}
+ +{{/oe.operators.0.output.useInputDataFrame}} + + + + + + + + + + {{#oe.operators.0.dataFrame}} + {{>partials/propertyTables}} + {{/oe.operators.0.dataFrame}} + +
Data Frame MemberTypeDescription
+ +{{/oe.operators.0.hasDataFrame}} + +{{#oe.operators.0.output.isEnum}} + +

{{{oe.operators.0.output.name}}}

+ +
{{{oe.operators.0.output.dataFrameDescription}}}
+ + + + + + + + + {{#oe.operators.0.output.enumFields}} + + + + + {{/oe.operators.0.output.enumFields}} + +
Field & ValueDescription
+ + {{{field&value}}} + + + {{{description}}} +
+ +{{/oe.operators.0.output.isEnum}} + diff --git a/template/api/partials/enum.tmpl.partial b/template/api/partials/enum.tmpl.partial new file mode 100644 index 0000000..66b28c6 --- /dev/null +++ b/template/api/partials/enum.tmpl.partial @@ -0,0 +1,38 @@ +{{#isEnum}} + +

+ {{name.0.value}} + {{#sourceurl}}{{/sourceurl}} +

+ +{{{oe.description}}} + +{{#oe.hasEnumFields}} + +

Fields

+ + + + + + + + + {{#oe.enumFields}} + + + + + {{/oe.enumFields}} + +
Field & ValueDescription
+ + {{{field&value}}} + + + {{{description}}} +
+ +{{/oe.hasEnumFields}} + +{{/isEnum}} \ No newline at end of file diff --git a/template/api/partials/propertyTables.tmpl.partial b/template/api/partials/propertyTables.tmpl.partial new file mode 100644 index 0000000..84d3b9e --- /dev/null +++ b/template/api/partials/propertyTables.tmpl.partial @@ -0,0 +1,37 @@ + + + + + {{{name}}} + + + + + + {{{type}}} + + + + + + {{{description}}} + + {{#hasEnum}} + +
+ + {{#enumFields}} + +
{{{field&value}}}
+ +
{{{description}}}
+ + {{/enumFields}} + +
+ + {{/hasEnum}} + + + + \ No newline at end of file diff --git a/template/api/toc.extension.js b/template/api/toc.extension.js new file mode 100644 index 0000000..cac0e81 --- /dev/null +++ b/template/api/toc.extension.js @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/** + * This method will be called at the start of exports.transform in toc.html.js and toc.json.js + */ +exports.preTransform = function (model) { + if (model.items[0].name === 'OpenEphys.Onix1'){ + if (model.items[0].items){ + itemsItemsLength = model.items[0].items.length; + let items = [{ + 'name': 'Infrastructural Operators', + 'items': []}, { + 'name': 'Breakout Board, Headstage, Etc. Configuration Operators', + 'items': []}, { + 'name': 'Data I/O Operators', + 'items': []}, { + 'name': 'Device Configuration Operators (Not Recommended)', + 'items': [] + }]; + for (let i = 0; i < itemsItemsLength; i++) { + globalYml = '~/api/' + model.items[0].items[i].topicUid + '.yml'; + if (model.items[0].items[i].name.includes('DataFrame') || + model.items[0].items[i].name.includes('DeviceFactory') || + model.items[0].items[i].name.includes('ContextTask') || + model.items[0].items[i].name.includes('DeviceNameConverter') || + model.items[0].items[i].name.includes('ConfigureDS90UB9x') || + model.items[0].items[i].name.includes('ConfigureFmcLinkController') || + model.items[0].items[i].name.includes('DeviceContext')){ + model.items[0].items[i].hide = true; + } + else if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'enum') { + model.items[0].items[i].hide = true; + } + else { + if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'class'){ + const inheritanceLength = model.__global._shared[globalYml].inheritance.length; + device = false; + hub = false; + for (let j = 0; j < inheritanceLength; j++){ + if (model.__global._shared[globalYml].inheritance[j].uid === 'OpenEphys.Onix1.SingleDeviceFactory'){ + device = true; + } + else if (model.__global._shared[globalYml].inheritance[j].uid === 'OpenEphys.Onix1.MultiDeviceFactory'){ + hub = true; + } + } + if (model.items[0].items[i].name.includes('CreateContext') || model.items[0].items[i].name.includes('StartAcquisition')){ + items[0].items.push(model.items[0].items[i]); + } + else if (device){ + items[3].items.push(model.items[0].items[i]); + } + else if (hub){ + items[1].items.push(model.items[0].items[i]); + } + else { + items[2].items.push(model.items[0].items[i]); + } + } + } + } + model.items[0].items = items; + } + } + return model; +} + +/** + * This method will be called at the end of exports.transform in toc.html.js and toc.json.js + */ +exports.postTransform = function (model) { + return model; +} From 3053524bfa331a14682b786678ab48868eb07863 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 10:08:05 -0700 Subject: [PATCH 02/29] Delete files not required for API template --- template/api/ManagedReference.overwrite.js | 5 -- template/api/toc.extension.js | 74 ---------------------- 2 files changed, 79 deletions(-) delete mode 100644 template/api/ManagedReference.overwrite.js delete mode 100644 template/api/toc.extension.js diff --git a/template/api/ManagedReference.overwrite.js b/template/api/ManagedReference.overwrite.js deleted file mode 100644 index ff7ef9d..0000000 --- a/template/api/ManagedReference.overwrite.js +++ /dev/null @@ -1,5 +0,0 @@ -exports.getOptions = function (model) { - return { - isShared: true - }; -} \ No newline at end of file diff --git a/template/api/toc.extension.js b/template/api/toc.extension.js deleted file mode 100644 index cac0e81..0000000 --- a/template/api/toc.extension.js +++ /dev/null @@ -1,74 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/** - * This method will be called at the start of exports.transform in toc.html.js and toc.json.js - */ -exports.preTransform = function (model) { - if (model.items[0].name === 'OpenEphys.Onix1'){ - if (model.items[0].items){ - itemsItemsLength = model.items[0].items.length; - let items = [{ - 'name': 'Infrastructural Operators', - 'items': []}, { - 'name': 'Breakout Board, Headstage, Etc. Configuration Operators', - 'items': []}, { - 'name': 'Data I/O Operators', - 'items': []}, { - 'name': 'Device Configuration Operators (Not Recommended)', - 'items': [] - }]; - for (let i = 0; i < itemsItemsLength; i++) { - globalYml = '~/api/' + model.items[0].items[i].topicUid + '.yml'; - if (model.items[0].items[i].name.includes('DataFrame') || - model.items[0].items[i].name.includes('DeviceFactory') || - model.items[0].items[i].name.includes('ContextTask') || - model.items[0].items[i].name.includes('DeviceNameConverter') || - model.items[0].items[i].name.includes('ConfigureDS90UB9x') || - model.items[0].items[i].name.includes('ConfigureFmcLinkController') || - model.items[0].items[i].name.includes('DeviceContext')){ - model.items[0].items[i].hide = true; - } - else if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'enum') { - model.items[0].items[i].hide = true; - } - else { - if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'class'){ - const inheritanceLength = model.__global._shared[globalYml].inheritance.length; - device = false; - hub = false; - for (let j = 0; j < inheritanceLength; j++){ - if (model.__global._shared[globalYml].inheritance[j].uid === 'OpenEphys.Onix1.SingleDeviceFactory'){ - device = true; - } - else if (model.__global._shared[globalYml].inheritance[j].uid === 'OpenEphys.Onix1.MultiDeviceFactory'){ - hub = true; - } - } - if (model.items[0].items[i].name.includes('CreateContext') || model.items[0].items[i].name.includes('StartAcquisition')){ - items[0].items.push(model.items[0].items[i]); - } - else if (device){ - items[3].items.push(model.items[0].items[i]); - } - else if (hub){ - items[1].items.push(model.items[0].items[i]); - } - else { - items[2].items.push(model.items[0].items[i]); - } - } - } - } - model.items[0].items = items; - } - } - return model; -} - -/** - * This method will be called at the end of exports.transform in toc.html.js and toc.json.js - */ -exports.postTransform = function (model) { - return model; -} From 3e629e3b511d35e6ebde20dfa0ccc56deaf35dc0 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 11:43:34 -0700 Subject: [PATCH 03/29] Add refactored Bonsai and Mref js extensions --- template/api/BonsaiCommon.js | 64 ++++++++++++++++++++++ template/api/ManagedReference.extension.js | 47 +--------------- 2 files changed, 67 insertions(+), 44 deletions(-) create mode 100644 template/api/BonsaiCommon.js diff --git a/template/api/BonsaiCommon.js b/template/api/BonsaiCommon.js new file mode 100644 index 0000000..9eb4ebf --- /dev/null +++ b/template/api/BonsaiCommon.js @@ -0,0 +1,64 @@ +// This module contains common functions utilised by the Docfx Template System for Bonsai API pages. + +exports.defineOperatorType = function defineOperatorType(model){ + // Define Bonsai operator types in documentation by checking for an explicit Category tag. If the class does not provide one, + // check the inheritance tree of the class. + let operatorType = {'source': false, 'combinator': false, 'sink': false, 'transform' : false}; + if (model.syntax && model.syntax.content[0].value){ + if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Source)]')){ + operatorType.source = true; + } + else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Combinator)]')){ + operatorType.combinator = true; + } + else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Sink)]')){ + operatorType.sink = true; + } + else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Transform)]')){ + operatorType.transform = true; + } + } + if (!(operatorType.source || operatorType.combinator || operatorType.sink || operatorType.transform)){ + if (model.inheritance){ + const inheritanceLength = model.inheritance.length; + for (let i = 0; i < inheritanceLength; i++){ + + // This section checks for common Bonsai operator type nodes. Ignore Bonsai.Combinator if Bonsai.Sink or Bonsai.Transform is present + // as many sink and transform operators inherit Bonsai.Combinator + if (model.inheritance[i].uid.includes('Bonsai.Source')){ + operatorType.source = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.Combinator')){ + operatorType.combinator = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.Sink')){ + operatorType.combinator = false; + operatorType.sink = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.Transform')){ + operatorType.combinator = false; + operatorType.transform = true; + } + + // This section checks unique Bonsai operator type nodes + else if (model.inheritance[i].uid.includes('Bonsai.WindowCombinator')){ + operatorType.combinator = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.IO.StreamSink')){ + operatorType.sink = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.IO.FileSink')){ + operatorType.sink = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.Dsp.ArrayTransform')){ + operatorType.transform = true; + } + } + } + } + + // Flag for showing Bonsai workflow container for Bonsai visible operators + operatorType.showWorkflow = operatorType.source | operatorType.combinator | operatorType.sink | operatorType.transform; + return operatorType; + } + diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index c5516c8..2f930d3 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +var BonsaiCommon = require('./BonsaiCommon.js') + function removeBottomMargin(str){ return str.split('').reverse().join('') .replace( ' Date: Wed, 14 Aug 2024 14:02:16 -0700 Subject: [PATCH 04/29] Add back required mref.overwrite.js --- template/api/ManagedReference.overwrite.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 template/api/ManagedReference.overwrite.js diff --git a/template/api/ManagedReference.overwrite.js b/template/api/ManagedReference.overwrite.js new file mode 100644 index 0000000..ff7ef9d --- /dev/null +++ b/template/api/ManagedReference.overwrite.js @@ -0,0 +1,5 @@ +exports.getOptions = function (model) { + return { + isShared: true + }; +} \ No newline at end of file From 0d08ec148a837f4c80239a83a4bc637d1a40513e Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 16:43:29 -0700 Subject: [PATCH 05/29] Remove OE specific code from define inputs and outputs --- template/api/ManagedReference.extension.js | 173 +-------------------- 1 file changed, 2 insertions(+), 171 deletions(-) diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 2f930d3..66e7b86 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -28,88 +28,7 @@ function replaceIObservableAndTSource(str){ // compile list of data for input --> o --> output diagrams function defineInputsAndOutputs(model){ operators = []; - if (model.oe.hubOrDevice === 'hub'){ - const hubChildrenLength = model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children.length; - for (let i = 0; i < hubChildrenLength; i++){ - if (model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].name[0].value.includes('Process')){ - description = [ - model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].summary, - model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].remarks - ].join(''); - } - input = {}; - if (model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters && model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0]){ - input = { - 'specName': replaceIObservableAndTSource(model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0].type.specName[0].value), - 'name': model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0].type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), - 'description': removeBottomMargin([ model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0].description, - model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.parameters[0].remarks].join(''))}; - input.internal = true; - } - output = {}; - dataFrame = []; - if (model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return){ - output = { - 'specName': replaceIObservableAndTSource(model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.type.specName[0].value), - 'name': model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), - 'description': removeBottomMargin([ model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.description, - model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.remarks].join(''))}; - output.internal = true; - outputYml = [ '~/api/', - model.__global._shared['~/api/OpenEphys.Onix1.MultiDeviceFactory.yml'].children[i].syntax.return.type.uid.replaceAll(/(\D*{)|(}$)/g, ''), - '.yml'].join(''); - if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['children'] && (model['__global']['_shared'][outputYml].type === 'class')){ - output.dataFrameDescription = [ - model['__global']['_shared'][outputYml].summary, - model['__global']['_shared'][outputYml].remarks].join(''); - const outputYmlChildrenLength = model['__global']['_shared'][outputYml]['children'].length; - for (let j = 0; j < outputYmlChildrenLength; j++){ - if (model['__global']['_shared'][outputYml]['children'][j].type === 'property'){ - potentialEnumYml = '~/api/' + model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.uid + '.yml'; - let enumFields = []; - if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ - enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); - } - if (enumFields.length > 0){ - output.dataFrameDescription = [ - model['__global']['_shared'][outputYml].summary, - model['__global']['_shared'][outputYml].remarks].join(''), - dataFrame.push({ - 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([ model['__global']['_shared'][outputYml]['children'][j].summary, - model['__global']['_shared'][outputYml]['children'][j].remarks].join('')), - 'enumFields': enumFields, - 'hasEnum': true - }); - } - else{ - dataFrame.push({ - 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([ model['__global']['_shared'][outputYml]['children'][j].summary, - model['__global']['_shared'][outputYml]['children'][j].remarks].join('')) - }); - } - } - } - } - } - } - if (Object.keys(input).length && Object.keys(dataFrame).length){ - operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasInput': true, 'hasDataFrame': true}); - } - else if (Object.keys(input).length){ - operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasInput': true}); - } - else if (Object.keys(dataFrame).length){ - operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasDataFrame': true}); - } - else{ - operators.push({'description': description, 'output': output}); - } - } - else if (model.children){ + if (model.children){ const childrenLength = model.children.length; for (let i = 0; i < childrenLength; i++){ if (model.children[i].uid.includes('Generate') || model.children[i].uid.includes('Process')){ @@ -122,86 +41,7 @@ function defineInputsAndOutputs(model){ 'description': removeBottomMargin([model.children[i].syntax.parameters[0].description, model.children[i].syntax.parameters[0].remarks].join('')) }; input.dataFrame = []; - if (model.__global._shared['~/api/OpenEphys.Onix1.' + input.name + '.yml']){ - input.internal = true; - inputYml = [ '~/api/', - model.children[i].syntax.parameters[0].type.uid.replaceAll(/(\D*{)|(}$)/g, ''), - '.yml'].join(''); - if (model['__global']['_shared'][inputYml] && model['__global']['_shared'][inputYml]['children'] && (model['__global']['_shared'][inputYml].type === 'class')){ - input.dataFrameDescription = [ - model['__global']['_shared'][inputYml].summary, - model['__global']['_shared'][inputYml].remarks - ].join(''); - const inputYmlChildrenLength = model['__global']['_shared'][inputYml]['children'].length; - for (let j = 0; j < inputYmlChildrenLength; j++){ - if (model['__global']['_shared'][inputYml]['children'][j] && model['__global']['_shared'][inputYml]['children'][j].type === 'property'){ - let enumFields = []; - if (model['__global']['_shared'][inputYml]['children'][j].syntax.parameters[0]){ - potentialEnumYml = '~/api/' + model['__global']['_shared'][inputYml]['children'][j].syntax.parameters[0].type.uid + '.yml'; - if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ - enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); - } - } - if (enumFields.length > 0){ - input.dataFrame.push({ - 'name': model['__global']['_shared'][inputYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][inputYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([ model['__global']['_shared'][inputYml]['children'][j].summary, - model['__global']['_shared'][inputYml]['children'][j].remarks].join('')), - 'enumFields': enumFields, - 'hasEnum': true - }); - } - else{ - input.dataFrame.push({ - 'name': model['__global']['_shared'][inputYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][inputYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([ model['__global']['_shared'][inputYml]['children'][j].summary, - model['__global']['_shared'][inputYml]['children'][j].remarks].join('')) - }); - } - } - } - } - else if (model['__global']['_shared'][inputYml] && model['__global']['_shared'][inputYml]['children'] && (model['__global']['_shared'][inputYml].type === 'enum')){ - input.internal = true; - input.dataFrameDescription = [ - model['__global']['_shared'][inputYml].summary, - model['__global']['_shared'][inputYml].remarks - ].join(''); - const inputYmlChildrenLength = model['__global']['_shared'][inputYml]['children'].length; - for (let j = 0; j < inputYmlChildrenLength; j++){ - if (model['__global']['_shared'][inputYml]['children'][j].type === 'property'){ - potentialEnumYml = '~/api/' + model['__global']['_shared'][inputYml]['children'][j].syntax.parameters[0].type.uid + '.yml'; - let enumFields = []; - if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ - enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); - } - if (enumFields.length > 0){ - dataFrame.push({ - 'name': model['__global']['_shared'][inputYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][inputYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([ model['__global']['_shared'][inputYml]['children'][j].summary, - model['__global']['_shared'][inputYml]['children'][j].remarks].join('')), - 'enumFields': enumFields, - 'hasEnum': true - }); - } - else{ - dataFrame.push({ - 'name': model['__global']['_shared'][inputYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][inputYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([ model['__global']['_shared'][inputYml]['children'][j].summary, - model['__global']['_shared'][inputYml]['children'][j].remarks].join('')) - }); - } - } - } - } - } - else { - input.external = true; - } + input.external = true; } if (model.children[i].syntax.return){ output = { @@ -503,15 +343,6 @@ exports.preTransform = function (model) { else { } - - if (operatorType.device) { - model.oe.hubOrDevice = 'device'; - model.oe.device = true; - } - else if (operatorType.hub){ - model.oe.hubOrDevice = 'hub'; - model.oe.hub = true; - } operators = defineInputsAndOutputs(model); if (operators.length > 0){ From 45e03d4e5bba2ef39744527c9f47215e14c24d24 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 18:06:12 -0700 Subject: [PATCH 06/29] Add missing source link for enums --- template/api/partials/enum.tmpl.partial | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/api/partials/enum.tmpl.partial b/template/api/partials/enum.tmpl.partial index 66b28c6..cf27bff 100644 --- a/template/api/partials/enum.tmpl.partial +++ b/template/api/partials/enum.tmpl.partial @@ -1,6 +1,6 @@ {{#isEnum}} -

+

{{name.0.value}} {{#sourceurl}}{{/sourceurl}}

From bebd2e0eb12b0762a53069d750262a5f52389a02 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 19:58:40 -0700 Subject: [PATCH 07/29] Simplify enum processing and strip OE specific code - The original template has code that enables display of enums values and description on some of the classes that use them - Some of it seems to be specific to OE nodes, but I have kept the one in the defineProperties function that applies generally --- template/api/ManagedReference.extension.js | 58 ++++------------------ template/api/partials/enum.tmpl.partial | 8 +-- 2 files changed, 14 insertions(+), 52 deletions(-) diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 66e7b86..df61cff 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -3,6 +3,7 @@ var BonsaiCommon = require('./BonsaiCommon.js') +// This function is important for stripping the extra line that is present in some fields function removeBottomMargin(str){ return str.split('').reverse().join('') .replace( ' 0){ - dataFrame.push({ - 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([ model['__global']['_shared'][outputYml]['children'][j].summary, - model['__global']['_shared'][outputYml]['children'][j].remarks].join('')), - 'enumFields': enumFields, - 'hasEnum': true - }); - } - else{ dataFrame.push({ 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, @@ -83,7 +68,6 @@ function defineInputsAndOutputs(model){ model['__global']['_shared'][outputYml]['children'][j].remarks].join('')) }); } - } } } if (dataFrame.length === 0 && input.dataFrame && input.dataFrame.length > 0){ @@ -116,16 +100,6 @@ function defineInputsAndOutputs(model){ } } } - else if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['children'] && (model['__global']['_shared'][outputYml].type === 'enum')){ - output.internal = true; - output.external = false; - output.dataFrameDescription = [ - model['__global']['_shared'][outputYml].summary, - model['__global']['_shared'][outputYml].remarks - ].join(''); - output.enumFields = defineEnumFields(model['__global']['_shared'][outputYml]); - output.isEnum = true; - } else if (!output.internal){ output.external = true; } @@ -160,26 +134,11 @@ function defineSubOperators(model){ let subProperties = []; for (let j = 0; j < subOperatorChildrenLength; j++){ if (model['__global']['_shared'][potentialSubOperatorYml]['children'][j].type === 'property'){ - let enumFields = []; - potentialEnumYml = '~/api/' + model['__global']['_shared'][potentialSubOperatorYml]['children'][j].syntax.return.type.uid + '.yml'; - if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ - enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); - } - if (enumFields.length > 0){ - subProperties.push({'name': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin( [model['__global']['_shared'][potentialSubOperatorYml]['children'][j].summary, - model['__global']['_shared'][potentialSubOperatorYml]['children'][j].remarks].join('')), - 'enumFields': enumFields, - 'hasEnum': true}); - } - else{ subProperties.push({'name': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].name[0].value, 'type': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].syntax.return.type.specName[0].value, 'description': removeBottomMargin( [model['__global']['_shared'][potentialSubOperatorYml]['children'][j].summary, model['__global']['_shared'][potentialSubOperatorYml]['children'][j].remarks].join('')) }); - } } } if (subProperties.length > 0){ @@ -212,6 +171,10 @@ function defineProperties(model){ const childrenLength = model.children.length; for (let i = 0; i < childrenLength; i++){ if (model.children[i].type === 'property'){ + + // this section adds enum members and summary to the property table if the property is an enum + // however doesnt always work (In Pulsepal Repo - Outputchannel enum is the only one out of 6 enums that doesnt work) + // bug present in original template so need to troubleshoot potentialEnumYml = '~/api/' + model['children'][i].syntax.return.type.uid + '.yml'; let enumFields = []; if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ @@ -226,6 +189,7 @@ function defineProperties(model){ 'hasEnum': true }); } + else { properties.push({ 'name': model.children[i].name[0].value, @@ -299,6 +263,8 @@ const swapElements = (array, index1, index2) => { array[index2] = temp; }; +// While enum fields can be accessed directly using the mustache template, this function is +// still important for stripping the extra line that is present in the summary/remarks field function defineEnumFields(model){ let enumFields = []; if (model.children){ @@ -393,12 +359,8 @@ exports.preTransform = function (model) { enumFields = defineEnumFields(model); if (enumFields.length > 0){ - model.oe.hasEnumFields = true; - model.oe.enumFields = enumFields; - } - - if (model.uid.includes('DeviceFactory')){ - model.showWorkflow = false; + model.hasEnumFields = true; + model.enumFields = enumFields; } return model; diff --git a/template/api/partials/enum.tmpl.partial b/template/api/partials/enum.tmpl.partial index cf27bff..32975ee 100644 --- a/template/api/partials/enum.tmpl.partial +++ b/template/api/partials/enum.tmpl.partial @@ -7,7 +7,7 @@ {{{oe.description}}} -{{#oe.hasEnumFields}} +{{#hasEnumFields}}

Fields

@@ -18,7 +18,7 @@ Description - {{#oe.enumFields}} + {{#enumFields}} @@ -29,10 +29,10 @@ {{{description}}} - {{/oe.enumFields}} + {{/enumFields}} -{{/oe.hasEnumFields}} +{{/hasEnumFields}} {{/isEnum}} \ No newline at end of file From 9a1f75dc4df8245d0efef6c43bda0be00e53c14c Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 22:07:12 -0700 Subject: [PATCH 08/29] Strip OE specific suboperator functions --- template/api/ManagedReference.extension.js | 88 ++-------------------- 1 file changed, 6 insertions(+), 82 deletions(-) diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index df61cff..67b2c87 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -122,48 +122,6 @@ function defineInputsAndOutputs(model){ return operators; } -function defineSubOperators(model){ - let subOperators = [] - if (model.children){ - const childrenLength = model.children.length; - for (let i = 0; i < childrenLength; i++){ - if (model.children[i].type === 'property'){ - potentialSubOperatorYml = '~/api/' + model.children[i].syntax.return.type.uid + '.yml'; - if (model['__global']['_shared'][potentialSubOperatorYml]){ - subOperatorChildrenLength = model['__global']['_shared'][potentialSubOperatorYml]['children'].length; - let subProperties = []; - for (let j = 0; j < subOperatorChildrenLength; j++){ - if (model['__global']['_shared'][potentialSubOperatorYml]['children'][j].type === 'property'){ - subProperties.push({'name': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][potentialSubOperatorYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin( [model['__global']['_shared'][potentialSubOperatorYml]['children'][j].summary, - model['__global']['_shared'][potentialSubOperatorYml]['children'][j].remarks].join('')) - }); - } - } - if (subProperties.length > 0){ - subOperators.push({ - 'object': model.children[i].name[0].value, - 'type': model.children[i].syntax.return.type.specName[0].value, - 'subProperties': subProperties, - 'hasSubProperties': true, - 'subOperator': true - }); - } - else if (model.__global._shared['~/api/' + model.children[i].name[0].value + '.yml']){ - subOperators.push({ - 'object': model.children[i].name[0].value, - 'type': model.children[i].syntax.return.type.specName[0].value, - 'subOperator': true - }); - } - } - } - } - } - return subOperators -} - // compile list of properties function defineProperties(model){ properties = []; @@ -172,7 +130,7 @@ function defineProperties(model){ for (let i = 0; i < childrenLength; i++){ if (model.children[i].type === 'property'){ - // this section adds enum members and summary to the property table if the property is an enum + // This section adds enum members and summary to the property table if the property is an enum // however doesnt always work (In Pulsepal Repo - Outputchannel enum is the only one out of 6 enums that doesnt work) // bug present in original template so need to troubleshoot potentialEnumYml = '~/api/' + model['children'][i].syntax.return.type.uid + '.yml'; @@ -189,7 +147,7 @@ function defineProperties(model){ 'hasEnum': true }); } - + // This adds the rest of the properties else { properties.push({ 'name': model.children[i].name[0].value, @@ -200,6 +158,7 @@ function defineProperties(model){ } } } + //check if this section is necessary if (model.inheritedMembers){ const inheritedMembersLength = model.inheritedMembers.length; for (let i = 0; i < inheritedMembersLength; i++){ @@ -224,6 +183,8 @@ function defineProperties(model){ return properties; } +// While docfx has an option to sort enum fields alphabetically, it does not have a similar option for class properties +// and this function provides that. function sortProperties(properties){ let propertyNames = []; let propertyNamesThatFitPattern = []; @@ -307,7 +268,6 @@ exports.preTransform = function (model) { model.showWorkflow = operatorType.showWorkflow; } else { - } operators = defineInputsAndOutputs(model); @@ -320,42 +280,6 @@ exports.preTransform = function (model) { model.oe.hasProperties = true; model.oe.properties = sortProperties(properties); } - - subOperators = defineSubOperators(model); - if (subOperators.length > 0){ - model.oe.hasSubOperators = true; - model.oe.subOperators = subOperators; - } - - if (model.oe.hasProperties && model.oe.hasSubOperators){ - subPropertyNames = []; - hubProperties = []; - const subOperatorsLength = model.oe.subOperators.length; - for (let i = 0; i < subOperatorsLength; i++){ - subPropertyNames.push(model.oe.subOperators[i].object); - } - const propertiesLength = model.oe.properties.length; - for (let i = 0; i < propertiesLength; i++){ - const subPropertyNamesLength = subPropertyNames.length; - propertyNotInSubOperator = false; - for (let j = 0; j < subPropertyNamesLength; j++){ - if (model.oe.properties[i].name === subPropertyNames[j]){ - propertyNotInSubOperator = true; - } - } - if (!propertyNotInSubOperator){ - hubProperties.push(model.oe.properties[i]); - } - } - if (hubProperties.length > 0){ - model.oe.subOperators.push({ - 'object': 'Misc', - 'subProperties': hubProperties, - 'hasSubProperties': true, - 'subOperator': false - }) - } - } enumFields = defineEnumFields(model); if (enumFields.length > 0){ @@ -371,4 +295,4 @@ exports.preTransform = function (model) { */ exports.postTransform = function (model) { return model; -} +} \ No newline at end of file From 428370d6e421b6eb89b86962eeb6ca7a09aa8391 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 22:49:11 -0700 Subject: [PATCH 09/29] Strip inherited members in properties table - Not sure what that section was doing but removing it didnt change anything, so it was probably OE specific --- template/api/ManagedReference.extension.js | 26 +------------- template/api/conceptual.html.primary.tmpl | 40 ---------------------- 2 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 template/api/conceptual.html.primary.tmpl diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 67b2c87..5aaf958 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -158,28 +158,6 @@ function defineProperties(model){ } } } - //check if this section is necessary - if (model.inheritedMembers){ - const inheritedMembersLength = model.inheritedMembers.length; - for (let i = 0; i < inheritedMembersLength; i++){ - if (model.inheritedMembers[i].type && (model.inheritedMembers[i].type === 'property')){ - let inheritedMemberYml = '~/api/' + model.inheritedMembers[i].parent + '.yml'; - if (model['__global']['_shared'][inheritedMemberYml]['children']){ - let inheritedMemberChildrenLength = model['__global']['_shared'][inheritedMemberYml]['children'].length; - for (let j = 0; j < inheritedMemberChildrenLength; j++){ - if (model.inheritedMembers[i].uid === model['__global']['_shared'][inheritedMemberYml]['children'][j].uid){ - properties.push( - {'name': model.inheritedMembers[i].name[0].value, - 'type': model['__global']['_shared'][inheritedMemberYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([model['__global']['_shared'][inheritedMemberYml]['children'][j].summary, - model['__global']['_shared'][inheritedMemberYml]['children'][j].remarks].join('')) - }); - } - } - } - } - } - } return properties; } @@ -267,9 +245,7 @@ exports.preTransform = function (model) { if (operatorType.showWorkflow) { model.showWorkflow = operatorType.showWorkflow; } - else { - } - + operators = defineInputsAndOutputs(model); if (operators.length > 0){ model.oe.operators = operators; diff --git a/template/api/conceptual.html.primary.tmpl b/template/api/conceptual.html.primary.tmpl deleted file mode 100644 index 921fadb..0000000 --- a/template/api/conceptual.html.primary.tmpl +++ /dev/null @@ -1,40 +0,0 @@ -{{!master(layout/_master.tmpl)}} - -

{{title}}

-{{#isGuide}} -
- -{{#workflow}} -{{#isDevice}} -{{>partials/device.workflow}} -{{/isDevice}} -{{#isHeadstage}} -{{>partials/headstage.workflow}} -
-{{>partials/headstage.devices}} -{{/isHeadstage}} -{{/workflow}} - -{{#visualize}} -
-

Visualize Data

- -{{#visualize_timeseries}} -{{>partials/device.visualize_timeseries}} -{{/visualize_timeseries}} - -{{#visualize_mat}} -{{>partials/device.visualize_mat}} -{{/visualize_mat}} - -{{#visualize_text}} -{{>partials/device.visualize_text}} -{{/visualize_text}} - -

Refer to Visualizing Data for more information on visualizers and how to download them.

-

Note that data will not be shown until a workflow is running. Check out Running a Workflow to see how to run a workflow.

- -{{/visualize}} -{{/isGuide}} - -{{{conceptual}}} \ No newline at end of file From 56accf53146d2dd6444e761d5c6a597d889d6f4b Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 23:18:07 -0700 Subject: [PATCH 10/29] Revert "Strip inherited members in properties table" This reverts commit 428370d6e421b6eb89b86962eeb6ca7a09aa8391. --- template/api/ManagedReference.extension.js | 26 +++++++++++++- template/api/conceptual.html.primary.tmpl | 40 ++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 template/api/conceptual.html.primary.tmpl diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 5aaf958..67b2c87 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -158,6 +158,28 @@ function defineProperties(model){ } } } + //check if this section is necessary + if (model.inheritedMembers){ + const inheritedMembersLength = model.inheritedMembers.length; + for (let i = 0; i < inheritedMembersLength; i++){ + if (model.inheritedMembers[i].type && (model.inheritedMembers[i].type === 'property')){ + let inheritedMemberYml = '~/api/' + model.inheritedMembers[i].parent + '.yml'; + if (model['__global']['_shared'][inheritedMemberYml]['children']){ + let inheritedMemberChildrenLength = model['__global']['_shared'][inheritedMemberYml]['children'].length; + for (let j = 0; j < inheritedMemberChildrenLength; j++){ + if (model.inheritedMembers[i].uid === model['__global']['_shared'][inheritedMemberYml]['children'][j].uid){ + properties.push( + {'name': model.inheritedMembers[i].name[0].value, + 'type': model['__global']['_shared'][inheritedMemberYml]['children'][j].syntax.return.type.specName[0].value, + 'description': removeBottomMargin([model['__global']['_shared'][inheritedMemberYml]['children'][j].summary, + model['__global']['_shared'][inheritedMemberYml]['children'][j].remarks].join('')) + }); + } + } + } + } + } + } return properties; } @@ -245,7 +267,9 @@ exports.preTransform = function (model) { if (operatorType.showWorkflow) { model.showWorkflow = operatorType.showWorkflow; } - + else { + } + operators = defineInputsAndOutputs(model); if (operators.length > 0){ model.oe.operators = operators; diff --git a/template/api/conceptual.html.primary.tmpl b/template/api/conceptual.html.primary.tmpl new file mode 100644 index 0000000..921fadb --- /dev/null +++ b/template/api/conceptual.html.primary.tmpl @@ -0,0 +1,40 @@ +{{!master(layout/_master.tmpl)}} + +

{{title}}

+{{#isGuide}} +
+ +{{#workflow}} +{{#isDevice}} +{{>partials/device.workflow}} +{{/isDevice}} +{{#isHeadstage}} +{{>partials/headstage.workflow}} +
+{{>partials/headstage.devices}} +{{/isHeadstage}} +{{/workflow}} + +{{#visualize}} +
+

Visualize Data

+ +{{#visualize_timeseries}} +{{>partials/device.visualize_timeseries}} +{{/visualize_timeseries}} + +{{#visualize_mat}} +{{>partials/device.visualize_mat}} +{{/visualize_mat}} + +{{#visualize_text}} +{{>partials/device.visualize_text}} +{{/visualize_text}} + +

Refer to Visualizing Data for more information on visualizers and how to download them.

+

Note that data will not be shown until a workflow is running. Check out Running a Workflow to see how to run a workflow.

+ +{{/visualize}} +{{/isGuide}} + +{{{conceptual}}} \ No newline at end of file From 18a26abe15a540b32a7cf0881be3548961382566 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 14 Aug 2024 23:31:39 -0700 Subject: [PATCH 11/29] Add doc comments for inherited members property table --- template/api/ManagedReference.extension.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 67b2c87..1073471 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -130,9 +130,10 @@ function defineProperties(model){ for (let i = 0; i < childrenLength; i++){ if (model.children[i].type === 'property'){ - // This section adds enum members and summary to the property table if the property is an enum - // however doesnt always work (In Pulsepal Repo - Outputchannel enum is the only one out of 6 enums that doesnt work) - // bug present in original template so need to troubleshoot + // This section adds enum fields and values to the property table if the property is an enum + // However doesnt always work (In Pulsepal Repo - Outputchannel enum doesnt show sometimes but the others do) + // Bug present in original template so need to troubleshoot + // Nice to have I think but not critical. potentialEnumYml = '~/api/' + model['children'][i].syntax.return.type.uid + '.yml'; let enumFields = []; if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ @@ -147,7 +148,7 @@ function defineProperties(model){ 'hasEnum': true }); } - // This adds the rest of the properties + // This adds the rest of the non-enum properties normally else { properties.push({ 'name': model.children[i].name[0].value, @@ -158,7 +159,8 @@ function defineProperties(model){ } } } - //check if this section is necessary + // This adds properties that belong to the members that it inherits (and which show up in the Bonsai side panel) + // On a default docfx website they dont show, so its pretty important. if (model.inheritedMembers){ const inheritedMembersLength = model.inheritedMembers.length; for (let i = 0; i < inheritedMembersLength; i++){ From b6b75e65f1ac6cef666773620f49e428f7cafb9d Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 10:37:22 -0700 Subject: [PATCH 12/29] Delete unnecessary conceptual markdown template --- template/api/conceptual.html.primary.tmpl | 40 ----------------------- 1 file changed, 40 deletions(-) delete mode 100644 template/api/conceptual.html.primary.tmpl diff --git a/template/api/conceptual.html.primary.tmpl b/template/api/conceptual.html.primary.tmpl deleted file mode 100644 index 921fadb..0000000 --- a/template/api/conceptual.html.primary.tmpl +++ /dev/null @@ -1,40 +0,0 @@ -{{!master(layout/_master.tmpl)}} - -

{{title}}

-{{#isGuide}} -
- -{{#workflow}} -{{#isDevice}} -{{>partials/device.workflow}} -{{/isDevice}} -{{#isHeadstage}} -{{>partials/headstage.workflow}} -
-{{>partials/headstage.devices}} -{{/isHeadstage}} -{{/workflow}} - -{{#visualize}} -
-

Visualize Data

- -{{#visualize_timeseries}} -{{>partials/device.visualize_timeseries}} -{{/visualize_timeseries}} - -{{#visualize_mat}} -{{>partials/device.visualize_mat}} -{{/visualize_mat}} - -{{#visualize_text}} -{{>partials/device.visualize_text}} -{{/visualize_text}} - -

Refer to Visualizing Data for more information on visualizers and how to download them.

-

Note that data will not be shown until a workflow is running. Check out Running a Workflow to see how to run a workflow.

- -{{/visualize}} -{{/isGuide}} - -{{{conceptual}}} \ No newline at end of file From 6c37c73b60ba43b5926b3cfdcd0ca96e227f6ed0 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 12:10:36 -0700 Subject: [PATCH 13/29] Add images and modified code for input/output diagram --- template/api/images/combinator-operator.svg | 67 ++++++++++++++++ template/api/images/right-arrow.svg | 87 ++++++++++++++++++++ template/api/images/sink-operator.svg | 86 ++++++++++++++++++++ template/api/images/source-operator.svg | 88 +++++++++++++++++++++ template/api/images/transform-operator.svg | 58 ++++++++++++++ template/api/partials/class.tmpl.partial | 13 --- template/api/partials/diagram.tmpl.partial | 6 +- 7 files changed, 389 insertions(+), 16 deletions(-) create mode 100644 template/api/images/combinator-operator.svg create mode 100644 template/api/images/right-arrow.svg create mode 100644 template/api/images/sink-operator.svg create mode 100644 template/api/images/source-operator.svg create mode 100644 template/api/images/transform-operator.svg diff --git a/template/api/images/combinator-operator.svg b/template/api/images/combinator-operator.svg new file mode 100644 index 0000000..4a4afac --- /dev/null +++ b/template/api/images/combinator-operator.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + diff --git a/template/api/images/right-arrow.svg b/template/api/images/right-arrow.svg new file mode 100644 index 0000000..85ebb00 --- /dev/null +++ b/template/api/images/right-arrow.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + diff --git a/template/api/images/sink-operator.svg b/template/api/images/sink-operator.svg new file mode 100644 index 0000000..918318c --- /dev/null +++ b/template/api/images/sink-operator.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + diff --git a/template/api/images/source-operator.svg b/template/api/images/source-operator.svg new file mode 100644 index 0000000..f39cb61 --- /dev/null +++ b/template/api/images/source-operator.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + diff --git a/template/api/images/transform-operator.svg b/template/api/images/transform-operator.svg new file mode 100644 index 0000000..43846fd --- /dev/null +++ b/template/api/images/transform-operator.svg @@ -0,0 +1,58 @@ + + diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index 0e25a93..b5b36be 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -12,19 +12,6 @@ {{/oe.operatorType}} -{{#oe.device}} - -
- This operator is a device operator. If you are using Open Ephys hardware, use an aggregate operator that corresponds to your particular headstage(s) instead. Aggregate operators confer the following benefits: -
    -
  • The address properties of aggregate operators are automatically configured whereas a device operators requires manual configuration of its address property. This improves ease of using Open Ephys hardware.
  • -
  • All devices that belong to a hub (which is a collection of devices i.e. a headstage or breakout board) are automatically included, excluding the possibility of omitting configuration of a device that belongs to a hub. This improves ease of using Open Ephys hardware.
  • -
  • The workflow is less cluttered with configuration operators as one aggregate operator can correspond to multiple device operators. This improves workflow readability.
  • -
-
- -{{/oe.device}} -
{{{oe.description}}}
{{#showWorkflow}} diff --git a/template/api/partials/diagram.tmpl.partial b/template/api/partials/diagram.tmpl.partial index c87f104..823b370 100644 --- a/template/api/partials/diagram.tmpl.partial +++ b/template/api/partials/diagram.tmpl.partial @@ -17,7 +17,7 @@ {{{description}}} - right-arrow + right-arrow {{/input}} @@ -27,7 +27,7 @@ - representation of a source, sink, or combinator operator + representation of a source, sink, or combinator operator @@ -36,7 +36,7 @@ {{#input}} @@ -27,7 +27,7 @@ @@ -39,7 +39,7 @@ right-arrow @@ -49,66 +49,4 @@
- right-arrow + right-arrow {{#output.internal}}
{{{output.name}}}
{{/output.internal}} From c5e70d743d7f0a0be6a2f79a929b5a2d8397d8af Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 15:21:04 -0700 Subject: [PATCH 14/29] Strip OE specific code from class partial template --- template/api/partials/class.tmpl.partial | 50 +----------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index b5b36be..7288cea 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -2,7 +2,7 @@

- {{name.0.value}} + {{name.0.value}}hi {{#sourceurl}}{{/sourceurl}}

{{#oe.operatorType}} @@ -21,56 +21,10 @@ {{#oe.operatorType}}

Inputs & Outputs

- {{>partials/diagram}} {{/oe.operatorType}} -{{#oe.hasSubOperators}} - -

Properties

- -
{{name.0.value}} is a aggregate operator. It comprises of the following sub-operators:
-
- -{{#oe.subOperators}} - -

{{{object}}}

- -{{#subOperator}} -
{{{object}}} is a {{{type}}} operator encapsulated by the {{name.0.value}} operator.
-{{/subOperator}} - -{{#hasSubProperties}} - - - - - - - - - - {{#subProperties}} - {{>partials/propertyTables}} - {{/subProperties}} - -
PropertyTypeDescription
- -{{/hasSubProperties}} - -{{^hasSubProperties}} - -
This subclass has no public properties.
- -{{/hasSubProperties}} - -{{/oe.subOperators}} - -{{/oe.hasSubOperators}} - -{{^oe.hasSubOperators}} - {{#oe.hasProperties}}

Properties

@@ -91,6 +45,4 @@ {{/oe.hasProperties}} -{{/oe.hasSubOperators}} - {{/isClass}} \ No newline at end of file From 1c8e075966b56dad19d6e313cc8ee9d449dab7f8 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 16:06:44 -0700 Subject: [PATCH 15/29] Remove operator tables from diagram partial template --- template/api/partials/class.tmpl.partial | 2 +- template/api/partials/diagram.tmpl.partial | 70 ++-------------------- 2 files changed, 5 insertions(+), 67 deletions(-) diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index 7288cea..fa89cd0 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -2,7 +2,7 @@

- {{name.0.value}}hi + {{name.0.value}} {{#sourceurl}}{{/sourceurl}}

{{#oe.operatorType}} diff --git a/template/api/partials/diagram.tmpl.partial b/template/api/partials/diagram.tmpl.partial index 823b370..b69e817 100644 --- a/template/api/partials/diagram.tmpl.partial +++ b/template/api/partials/diagram.tmpl.partial @@ -12,7 +12,7 @@
- {{#internal}}
{{{name}}}
{{/internal}} + {{#internal}}
{{{specName}}}
{{/internal}} {{#external}}
{{{specName}}}
{{/external}} {{{description}}}
- representation of a source, sink, or combinator operator + representation of a source, sink, transform or combinator operator - {{#output.internal}}
{{{output.name}}}
{{/output.internal}} + {{#output.internal}}
{{{output.specName}}}
{{/output.internal}} {{#output.external}}
{{{output.specName}}}
{{/output.external}}
{{{output.description}}}
-{{/oe.operators}} - -{{#oe.operators.0.hasDataFrame}} -{{^oe.operators.0.output.useInputDataFrame}} - -

{{{oe.operators.0.output.name}}}

-
{{{oe.operators.0.output.dataFrameDescription}}}
- -{{/oe.operators.0.output.useInputDataFrame}} - -{{#oe.operators.0.output.useInputDataFrame}} - -

{{{oe.operators.0.input.name}}}

-
{{{oe.operators.0.input.dataFrameDescription}}}
- -{{/oe.operators.0.output.useInputDataFrame}} - - - - - - - - - - {{#oe.operators.0.dataFrame}} - {{>partials/propertyTables}} - {{/oe.operators.0.dataFrame}} - -
Data Frame MemberTypeDescription
- -{{/oe.operators.0.hasDataFrame}} - -{{#oe.operators.0.output.isEnum}} - -

{{{oe.operators.0.output.name}}}

- -
{{{oe.operators.0.output.dataFrameDescription}}}
- - - - - - - - - {{#oe.operators.0.output.enumFields}} - - - - - {{/oe.operators.0.output.enumFields}} - -
Field & ValueDescription
- - {{{field&value}}} - - - {{{description}}} -
- -{{/oe.operators.0.output.isEnum}} - +{{/oe.operators}} \ No newline at end of file From a575f788b3e5577c366aca0b528283c2c315199f Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 16:30:20 -0700 Subject: [PATCH 16/29] Replace OE with Bonsai in variable names --- template/api/ManagedReference.extension.js | 22 +++++++++--------- template/api/partials/class.tmpl.partial | 26 +++++++++++----------- template/api/partials/diagram.tmpl.partial | 6 ++--- template/api/partials/enum.tmpl.partial | 10 ++++----- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 1073471..6fdb303 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -251,42 +251,42 @@ function defineEnumFields(model){ */ exports.preTransform = function (model) { - model.oe = {}; + model.bonsai = {}; - model.oe.description = [model.summary, model.remarks].join(''); + model.bonsai.description = [model.summary, model.remarks].join(''); operatorType = BonsaiCommon.defineOperatorType(model); if (operatorType.source){ - model.oe.operatorType = 'source'; + model.bonsai.operatorType = 'source'; } else if (operatorType.sink){ - model.oe.operatorType = 'sink'; + model.bonsai.operatorType = 'sink'; } else if (operatorType.combinator){ - model.oe.operatorType = 'combinator'; + model.bonsai.operatorType = 'combinator'; } if (operatorType.showWorkflow) { - model.showWorkflow = operatorType.showWorkflow; + model.bonsai.showWorkflow = operatorType.showWorkflow; } else { } operators = defineInputsAndOutputs(model); if (operators.length > 0){ - model.oe.operators = operators; + model.bonsai.operators = operators; } properties = defineProperties(model); if (properties.length > 0){ - model.oe.hasProperties = true; - model.oe.properties = sortProperties(properties); + model.bonsai.hasProperties = true; + model.bonsai.properties = sortProperties(properties); } enumFields = defineEnumFields(model); if (enumFields.length > 0){ - model.hasEnumFields = true; - model.enumFields = enumFields; + model.bonsai.hasEnumFields = true; + model.bonsai.enumFields = enumFields; } return model; diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index fa89cd0..bc8e2b0 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -2,30 +2,30 @@

- {{name.0.value}} + {{name.0.value}}hi {{#sourceurl}}{{/sourceurl}}

- {{#oe.operatorType}} + {{#bonsai.operatorType}}

- {{oe.operatorType}} Operator + {{bonsai.operatorType}} Operator

- {{/oe.operatorType}} + {{/bonsai.operatorType}}
-
{{{oe.description}}}
+
{{{bonsai.description}}}
-{{#showWorkflow}} +{{#bonsai.showWorkflow}}

{{name.0.value}} Workflow

-{{/showWorkflow}} +{{/bonsai.showWorkflow}} -{{#oe.operatorType}} +{{#bonsai.operatorType}}

Inputs & Outputs

{{>partials/diagram}} -{{/oe.operatorType}} +{{/bonsai.operatorType}} -{{#oe.hasProperties}} +{{#bonsai.hasProperties}}

Properties

@@ -37,12 +37,12 @@ Description - {{#oe.properties}} + {{#bonsai.properties}} {{>partials/propertyTables}} - {{/oe.properties}} + {{/bonsai.properties}} -{{/oe.hasProperties}} +{{/bonsai.hasProperties}} {{/isClass}} \ No newline at end of file diff --git a/template/api/partials/diagram.tmpl.partial b/template/api/partials/diagram.tmpl.partial index b69e817..9e621e9 100644 --- a/template/api/partials/diagram.tmpl.partial +++ b/template/api/partials/diagram.tmpl.partial @@ -1,4 +1,4 @@ -{{#oe.operators}} +{{#bonsai.operators}}
{{{description}}}
@@ -27,7 +27,7 @@ - representation of a source, sink, transform or combinator operator + representation of a source, sink, transform or combinator operator @@ -49,4 +49,4 @@ -{{/oe.operators}} \ No newline at end of file +{{/bonsai.operators}} \ No newline at end of file diff --git a/template/api/partials/enum.tmpl.partial b/template/api/partials/enum.tmpl.partial index 32975ee..c2ef63e 100644 --- a/template/api/partials/enum.tmpl.partial +++ b/template/api/partials/enum.tmpl.partial @@ -5,9 +5,9 @@ {{#sourceurl}}{{/sourceurl}} -{{{oe.description}}} +{{{bonsai.description}}} -{{#hasEnumFields}} +{{#bonsai.hasEnumFields}}

Fields

@@ -18,7 +18,7 @@ Description - {{#enumFields}} + {{#bonsai.enumFields}} @@ -29,10 +29,10 @@ {{{description}}} - {{/enumFields}} + {{/bonsai.enumFields}} -{{/hasEnumFields}} +{{/bonsai.hasEnumFields}} {{/isEnum}} \ No newline at end of file From 10337fd15cfbecf382f966a8fc122210dd35bdcb Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 18:14:47 -0700 Subject: [PATCH 17/29] Remove dataframe ref in defineinputoutput --- template/api/ManagedReference.extension.js | 58 +--------------------- template/api/partials/class.tmpl.partial | 2 +- 2 files changed, 3 insertions(+), 57 deletions(-) diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 6fdb303..d8b5532 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -41,7 +41,6 @@ function defineInputsAndOutputs(model){ 'name': model.children[i].syntax.parameters[0].type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), 'description': removeBottomMargin([model.children[i].syntax.parameters[0].description, model.children[i].syntax.parameters[0].remarks].join('')) }; - input.dataFrame = []; input.external = true; } if (model.children[i].syntax.return){ @@ -49,69 +48,18 @@ function defineInputsAndOutputs(model){ 'specName': replaceIObservableAndTSource(model.children[i].syntax.return.type.specName[0].value), 'name': model.children[i].syntax.return.type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), 'description': removeBottomMargin([model.children[i].syntax.return.description, model.children[i].syntax.return.remarks].join(''))}; - dataFrame = []; outputYml = [ '~/api/', model.children[i].syntax.return.type.uid.replaceAll(/(\D*{)|(}$)/g, ''), '.yml'].join(''); if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['children'] && (model['__global']['_shared'][outputYml].type === 'class')){ output.internal = true; - output.dataFrameDescription = [ - model['__global']['_shared'][outputYml].summary, - model['__global']['_shared'][outputYml].remarks].join(''); - const outputYmlChildrenLength = model['__global']['_shared'][outputYml]['children'].length; - for (let j = 0; j < outputYmlChildrenLength; j++){ - if (model['__global']['_shared'][outputYml]['children'][j].type === 'property'){ - dataFrame.push({ - 'name': model['__global']['_shared'][outputYml]['children'][j].name[0].value, - 'type': model['__global']['_shared'][outputYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([ model['__global']['_shared'][outputYml]['children'][j].summary, - model['__global']['_shared'][outputYml]['children'][j].remarks].join('')) - }); - } - } - } - if (dataFrame.length === 0 && input.dataFrame && input.dataFrame.length > 0){ - dataFrame = input.dataFrame; - output.useInputDataFrame = true;; - } - else if (!output.internal) { - output.external = true; - } - if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['inheritedMembers']){ - output.internal = true; - output.external = false; - const inheritedMembersLength = model['__global']['_shared'][outputYml]['inheritedMembers'].length; - for (let j = 0; j < inheritedMembersLength; j++){ - if (model['__global']['_shared'][outputYml]['inheritedMembers'][j].type === 'property'){ - let inheritedMemberYml = '~/api/' + model['__global']['_shared'][outputYml]['inheritedMembers'][j].parent + '.yml'; - if (model['__global']['_shared'][inheritedMemberYml]['children']){ - let inheritedMemberChildrenLength = model['__global']['_shared'][inheritedMemberYml]['children'].length; - for (let k = 0; k < inheritedMemberChildrenLength; k++){ - if (model['__global']['_shared'][outputYml]['inheritedMembers'][j].uid === model['__global']['_shared'][inheritedMemberYml]['children'][k].uid){ - dataFrame.push({ - 'name': model['__global']['_shared'][outputYml]['inheritedMembers'][j].name[0].value, - 'type': model['__global']['_shared'][inheritedMemberYml]['children'][k].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([model['__global']['_shared'][inheritedMemberYml]['children'][k].summary, - model['__global']['_shared'][inheritedMemberYml]['children'][k].remarks].join('')) - }); - } - } - } - } - } } else if (!output.internal){ output.external = true; } } - if (Object.keys(input).length && Object.keys(dataFrame).length){ - operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasInput': true, 'hasDataFrame': true}); - } - else if (Object.keys(input).length){ - operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasInput': true}); - } - else if (Object.keys(dataFrame).length){ - operators.push({'description': description, 'input': input, 'output': output, 'dataFrame': dataFrame, 'hasDataFrame': true}); + if (Object.keys(input).length){ + operators.push({'description': description, 'input': input, 'output': output, 'hasInput': true}); } else { operators.push({'description': description, 'output': output}); @@ -269,8 +217,6 @@ exports.preTransform = function (model) { if (operatorType.showWorkflow) { model.bonsai.showWorkflow = operatorType.showWorkflow; } - else { - } operators = defineInputsAndOutputs(model); if (operators.length > 0){ diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index bc8e2b0..6acf8a2 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -2,7 +2,7 @@

- {{name.0.value}}hi + {{name.0.value}} {{#sourceurl}}{{/sourceurl}}

{{#bonsai.operatorType}} From 031e25dc1bff7cc01ee3b0645d0c5096609aa81e Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 18:20:32 -0700 Subject: [PATCH 18/29] Minor code cleanup, finished conversion of template - Final version of OE template that retains all the features we want to port over - From here on out I am adding new features --- template/api/partials/propertyTables.tmpl.partial | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/template/api/partials/propertyTables.tmpl.partial b/template/api/partials/propertyTables.tmpl.partial index 84d3b9e..fe8b055 100644 --- a/template/api/partials/propertyTables.tmpl.partial +++ b/template/api/partials/propertyTables.tmpl.partial @@ -1,37 +1,26 @@ - {{{name}}} - - {{{type}}} - - {{{description}}} {{#hasEnum}} -
{{#enumFields}} -
{{{field&value}}}
-
{{{description}}}
- {{/enumFields}}
- {{/hasEnum}} - \ No newline at end of file From 1094df65c59569f0a77eb8ffbc93e7d8e69f1762 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 23:03:03 -0700 Subject: [PATCH 19/29] Add relationships to classes/enums - Adds namespace and definitions - Add inheritance, implements, and derived classes, but leaves out inherited members --- template/api/partials/class.tmpl.partial | 48 ++++++++++++++++++++++++ template/api/partials/enum.tmpl.partial | 7 ++++ 2 files changed, 55 insertions(+) diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index 6acf8a2..1405e6d 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -45,4 +45,52 @@ {{/bonsai.hasProperties}} +

Relationships

+
+
{{__global.namespace}} - {{{namespace.specName.0.value}}}
+ {{#assemblies.0}}
{{__global.assembly}} - {{assemblies.0}}.dll
{{/assemblies.0}} +
+ +{{#inheritance.0}} +
+
{{__global.inheritance}}
+
+{{/inheritance.0}} +{{#inheritance}} +
{{{specName.0.value}}}
+{{/inheritance}} +
{{name.0.value}}
+{{#inheritance.0}} +
+
+{{/inheritance.0}} + + +{{#implements.0}} +
+
{{__global.implements}}
+
+{{/implements.0}} +{{#implements}} +
{{{specName.0.value}}}
+{{/implements}} +{{#implements.0}} +
+
+{{/implements.0}} + +{{#derivedClasses.0}} +
+
{{__global.derived}}
+
+{{/derivedClasses.0}} +{{#derivedClasses}} +
{{{specName.0.value}}}
+{{/derivedClasses}} +{{#derivedClasses.0}} +
+
+{{/derivedClasses.0}} + + {{/isClass}} \ No newline at end of file diff --git a/template/api/partials/enum.tmpl.partial b/template/api/partials/enum.tmpl.partial index c2ef63e..f2b2e4d 100644 --- a/template/api/partials/enum.tmpl.partial +++ b/template/api/partials/enum.tmpl.partial @@ -35,4 +35,11 @@ {{/bonsai.hasEnumFields}} +

Relationships

+
+
{{__global.namespace}} - {{{namespace.specName.0.value}}}
+ {{#assemblies.0}}
{{__global.assembly}} - {{assemblies.0}}.dll
{{/assemblies.0}} +
+ + {{/isEnum}} \ No newline at end of file From 790470940d27c968e1b4fa2547bc4318b8bec179 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 15 Aug 2024 23:16:37 -0700 Subject: [PATCH 20/29] Add constructors to classes --- template/api/partials/class.tmpl.partial | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index 1405e6d..965ea0e 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -45,6 +45,32 @@ {{/bonsai.hasProperties}} +{{#children}} +{{#inConstructor}} +{{#children}} +

Constructors

+ + + + + + + + + + +
ConstructorsParameters
+ {{{specName.0.value}}}{{{summary}}} + + {{#syntax.parameters}} + {{{type.specName.0.value}}}{{{description}}} + {{/syntax.parameters}} +
+ +{{/children}} +{{/inConstructor}} +{{/children}} +

Relationships

{{__global.namespace}} - {{{namespace.specName.0.value}}}
From 6e2ff2a860fce8d3e68d1d30cf05a7476e601be2 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Sun, 18 Aug 2024 17:52:09 -0700 Subject: [PATCH 21/29] Refactor defineOperatorType function Co-authored-by: Cris --- template/api/BonsaiCommon.js | 70 ++++------------------ template/api/ManagedReference.extension.js | 23 +++---- 2 files changed, 22 insertions(+), 71 deletions(-) diff --git a/template/api/BonsaiCommon.js b/template/api/BonsaiCommon.js index 9eb4ebf..35da095 100644 --- a/template/api/BonsaiCommon.js +++ b/template/api/BonsaiCommon.js @@ -1,64 +1,20 @@ // This module contains common functions utilised by the Docfx Template System for Bonsai API pages. exports.defineOperatorType = function defineOperatorType(model){ - // Define Bonsai operator types in documentation by checking for an explicit Category tag. If the class does not provide one, - // check the inheritance tree of the class. - let operatorType = {'source': false, 'combinator': false, 'sink': false, 'transform' : false}; - if (model.syntax && model.syntax.content[0].value){ - if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Source)]')){ - operatorType.source = true; - } - else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Combinator)]')){ - operatorType.combinator = true; - } - else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Sink)]')){ - operatorType.sink = true; - } - else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Transform)]')){ - operatorType.transform = true; - } - } - if (!(operatorType.source || operatorType.combinator || operatorType.sink || operatorType.transform)){ - if (model.inheritance){ - const inheritanceLength = model.inheritance.length; - for (let i = 0; i < inheritanceLength; i++){ + // Define Bonsai operator types in documentation by checking for an explicit Category tag. If the class does not provide one, + // check the inheritance tree of the class. - // This section checks for common Bonsai operator type nodes. Ignore Bonsai.Combinator if Bonsai.Sink or Bonsai.Transform is present - // as many sink and transform operators inherit Bonsai.Combinator - if (model.inheritance[i].uid.includes('Bonsai.Source')){ - operatorType.source = true; - } - else if (model.inheritance[i].uid.includes('Bonsai.Combinator')){ - operatorType.combinator = true; - } - else if (model.inheritance[i].uid.includes('Bonsai.Sink')){ - operatorType.combinator = false; - operatorType.sink = true; - } - else if (model.inheritance[i].uid.includes('Bonsai.Transform')){ - operatorType.combinator = false; - operatorType.transform = true; - } + const checkForCategory = (category) => model.syntax?.content[0].value.includes(`[WorkflowElementCategory(ElementCategory.${category})]`); + const checkInheritance = (inheritance) => model.inheritance?.some(inherited => inherited.uid.includes(inheritance)); - // This section checks unique Bonsai operator type nodes - else if (model.inheritance[i].uid.includes('Bonsai.WindowCombinator')){ - operatorType.combinator = true; - } - else if (model.inheritance[i].uid.includes('Bonsai.IO.StreamSink')){ - operatorType.sink = true; - } - else if (model.inheritance[i].uid.includes('Bonsai.IO.FileSink')){ - operatorType.sink = true; - } - else if (model.inheritance[i].uid.includes('Bonsai.Dsp.ArrayTransform')){ - operatorType.transform = true; - } - } - } - } + source = checkForCategory('Source') || checkInheritance('Bonsai.Source'); + sink = checkForCategory('Sink') || checkInheritance('Bonsai.Sink') || checkInheritance('Bonsai.IO.StreamSink') || checkInheritance('Bonsai.IO.FileSink'); + combinator = checkForCategory('Combinator') || checkInheritance('Bonsai.Combinator') || checkInheritance('Bonsai.WindowCombinator'); + transform = checkForCategory('Transform') || checkInheritance('Bonsai.Transform') || checkInheritance('Bonsai.Transform'); - // Flag for showing Bonsai workflow container for Bonsai visible operators - operatorType.showWorkflow = operatorType.source | operatorType.combinator | operatorType.sink | operatorType.transform; - return operatorType; - } + let operatorType = {} + operatorType.type = sink ? 'sink' : source ? 'source' : transform ? 'transform' : combinator ? 'combinator' : false ; + operatorType.showWorkflow = !!operatorType.type + return operatorType; +} \ No newline at end of file diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index d8b5532..38e2756 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -4,12 +4,12 @@ var BonsaiCommon = require('./BonsaiCommon.js') // This function is important for stripping the extra line that is present in some fields -function removeBottomMargin(str){ - return str.split('').reverse().join('') - .replace( ' Date: Mon, 19 Aug 2024 22:57:25 -0700 Subject: [PATCH 22/29] Refactor some functions - replaceIObservableAndTSource edited to fit new refactored functions - sortProperties and defineEnumFields refactored Co-authored-by: Cris --- template/api/ManagedReference.extension.js | 144 +++++++-------------- template/api/partials/diagram.tmpl.partial | 6 +- 2 files changed, 50 insertions(+), 100 deletions(-) diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 38e2756..b505806 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -13,8 +13,13 @@ function removeBottomMargin(str) { } // Strip IObservable and replace 'TSource' with 'Anything' +// Added a null check to return an empty string to avoid undefined errors in new refactored code +// Consider replace "Anything" with "Observable" or "Any Observable" with a link to the observable guide function replaceIObservableAndTSource(str){ - if (str.includes('IGroupedObservable')){ + if (!str) { + return ''; + } + else if (str.includes('IGroupedObservable')){ const re = new RegExp(' o --> output diagrams +// this function is a revised version of cris's refactored function that restores the original values (specname, description) +// which were removed function defineInputsAndOutputs(model){ - operators = []; - if (model.children){ - const childrenLength = model.children.length; - for (let i = 0; i < childrenLength; i++){ - if (model.children[i].uid.includes('Generate') || model.children[i].uid.includes('Process')){ - description = [model.children[i].summary, model.children[i].remarks].join(''); - input = {}; - if (model.children[i].syntax.parameters && model.children[i].syntax.parameters[0]){ - input = { - 'specName': replaceIObservableAndTSource(model.children[i].syntax.parameters[0].type.specName[0].value), - 'name': model.children[i].syntax.parameters[0].type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), - 'description': removeBottomMargin([model.children[i].syntax.parameters[0].description, model.children[i].syntax.parameters[0].remarks].join('')) - }; - input.external = true; - } - if (model.children[i].syntax.return){ - output = { - 'specName': replaceIObservableAndTSource(model.children[i].syntax.return.type.specName[0].value), - 'name': model.children[i].syntax.return.type.name[0].value.replaceAll(/(IObservable<)|(>)/g, ''), - 'description': removeBottomMargin([model.children[i].syntax.return.description, model.children[i].syntax.return.remarks].join(''))}; - outputYml = [ '~/api/', - model.children[i].syntax.return.type.uid.replaceAll(/(\D*{)|(}$)/g, ''), - '.yml'].join(''); - if (model['__global']['_shared'][outputYml] && model['__global']['_shared'][outputYml]['children'] && (model['__global']['_shared'][outputYml].type === 'class')){ - output.internal = true; - } - else if (!output.internal){ - output.external = true; - } - } - if (Object.keys(input).length){ - operators.push({'description': description, 'input': input, 'output': output, 'hasInput': true}); - } - else { - operators.push({'description': description, 'output': output}); - } + overloads = model.children + .filter(child => child.name[0].value.includes('Process') || child.name[0].value.includes('Generate')) + .map(child => ({ + 'description': [child.summary, child.remarks].join(''), + 'input': { + 'specName': replaceIObservableAndTSource(child.syntax?.parameters[0].type.specName[0].value), + 'description': removeBottomMargin([child.syntax?.parameters[0].description, child.syntax?.parameters[0].remarks].join('')) + }, + 'output': { + 'specName': replaceIObservableAndTSource(child.syntax.return.type.specName[0].value), + 'description': removeBottomMargin([child.syntax.return.description, child.syntax.return.remarks].join('')), } - } - } - return operators; + })) + return overloads; } // compile list of properties @@ -133,67 +113,39 @@ function defineProperties(model){ return properties; } -// While docfx has an option to sort enum fields alphabetically, it does not have a similar option for class properties -// and this function provides that. -function sortProperties(properties){ - let propertyNames = []; - let propertyNamesThatFitPattern = []; - const propertiesLength = properties.length; - for (let i = 0; i < propertiesLength; i++){ - propertyNames.push([properties[i].name, - /\D+\d+$/.test(properties[i].name), - String(properties[i].name.match(/\D+/)), - Number(properties[i].name.match(/\d+$/))]); - } - for (let i = 0; i < propertiesLength; i++){ - if (propertyNames[i][1]){ - if (!propertyNamesThatFitPattern.includes(propertyNames[i][2])){ - propertyNamesThatFitPattern.push(propertyNames[i][2]); - } - } - } - const propertyNamesThatFitPatternLength = propertyNamesThatFitPattern.length; - for (let j = 0; j < propertyNamesThatFitPatternLength; j++){ - for (let i = 1; i < propertiesLength; i++){ - for (let k = i; k > 0; k--){ - if ((propertyNames[k][2] === propertyNamesThatFitPattern[j]) && (propertyNames[k - 1][2] === propertyNamesThatFitPattern[j])){ - if (propertyNames[k][3] < propertyNames[k - 1][3]){ - swapElements(properties, k, k - 1); - swapElements(propertyNames, k, k - 1); // why does this need to be here for this sortProperties function to work? - } - } - } +// Properties are usually already listed in declaration order which mirrors Bonsai UI. +// However a bug in docfx messes up properties that have a numeric endvalue ie Device10 < Device2 +// and this function fixes that. +function sortProperties(properties) { + return properties.sort((a, b) => { + const regex = /\D+|\d+$/g; + + // Extract parts for property 'a' + const [prefixA, numberA] = a.name.match(regex); + const numA = Number(numberA); + + // Extract parts for property 'b' + const [prefixB, numberB] = b.name.match(regex); + const numB = Number(numberB); + + // If prefix is the same, compare numbers + if (prefixA == prefixB) { + return numA - numB; } - } - return properties; + }); } -const swapElements = (array, index1, index2) => { - const temp = array[index1]; - array[index1] = array[index2]; - array[index2] = temp; -}; - // While enum fields can be accessed directly using the mustache template, this function is // still important for stripping the extra line that is present in the summary/remarks field function defineEnumFields(model){ - let enumFields = []; - if (model.children){ - const childrenLength = model.children.length; - for (let i = 0; i < childrenLength; i++){ - if (model.children[i].type === 'field'){ - enumFields.push({ - 'field&value': model.children[i].syntax.content[0].value, - 'description': removeBottomMargin([ model.children[i].summary, - model.children[i].remarks].join('')) - }); - } - } - } - return enumFields; + return model.children + .filter(child => child.type === 'field') + .map(child => ({ + 'field&value': child.syntax.content[0].value, + 'enumDescription': removeBottomMargin([child.summary, child.remarks].join('')) + })); } - /** * This method will be called at the start of exports.transform in ManagedReference.html.primary.js */ @@ -204,9 +156,9 @@ exports.preTransform = function (model) { model.bonsai.description = [model.summary, model.remarks].join(''); operatorType = BonsaiCommon.defineOperatorType(model); - + if (operatorType.type){ - model.bonsai.operatorType = operatorType.type + model.bonsai.operatorType = operatorType.type; } if (operatorType.showWorkflow) { diff --git a/template/api/partials/diagram.tmpl.partial b/template/api/partials/diagram.tmpl.partial index 9e621e9..915b6c1 100644 --- a/template/api/partials/diagram.tmpl.partial +++ b/template/api/partials/diagram.tmpl.partial @@ -12,8 +12,7 @@ {{#input}} - {{#internal}}
{{{specName}}}
{{/internal}} - {{#external}}
{{{specName}}}
{{/external}} +
{{{specName}}}
{{{description}}} @@ -39,8 +38,7 @@ right-arrow - {{#output.internal}}
{{{output.specName}}}
{{/output.internal}} - {{#output.external}}
{{{output.specName}}}
{{/output.external}} +
{{{output.specName}}}
{{{output.description}}}
From ebcef62fb65496061e4037269ad8f31ee4f15c87 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 22 Aug 2024 13:02:46 -0700 Subject: [PATCH 23/29] Refactor functions, add styles.css for template table formatting Co-authored-by: Cris Co-authored-by: Brandon Parks --- template/api/BonsaiCommon.js | 20 --- template/api/ManagedReference.extension.js | 150 +++++++++--------- template/api/partials/class.tmpl.partial | 2 + template/api/partials/enum.tmpl.partial | 2 +- .../api/partials/propertyTables.tmpl.partial | 29 ++-- template/api/styles/styles.css | 35 ++++ 6 files changed, 125 insertions(+), 113 deletions(-) delete mode 100644 template/api/BonsaiCommon.js create mode 100644 template/api/styles/styles.css diff --git a/template/api/BonsaiCommon.js b/template/api/BonsaiCommon.js deleted file mode 100644 index 35da095..0000000 --- a/template/api/BonsaiCommon.js +++ /dev/null @@ -1,20 +0,0 @@ -// This module contains common functions utilised by the Docfx Template System for Bonsai API pages. - -exports.defineOperatorType = function defineOperatorType(model){ - // Define Bonsai operator types in documentation by checking for an explicit Category tag. If the class does not provide one, - // check the inheritance tree of the class. - - const checkForCategory = (category) => model.syntax?.content[0].value.includes(`[WorkflowElementCategory(ElementCategory.${category})]`); - const checkInheritance = (inheritance) => model.inheritance?.some(inherited => inherited.uid.includes(inheritance)); - - source = checkForCategory('Source') || checkInheritance('Bonsai.Source'); - sink = checkForCategory('Sink') || checkInheritance('Bonsai.Sink') || checkInheritance('Bonsai.IO.StreamSink') || checkInheritance('Bonsai.IO.FileSink'); - combinator = checkForCategory('Combinator') || checkInheritance('Bonsai.Combinator') || checkInheritance('Bonsai.WindowCombinator'); - transform = checkForCategory('Transform') || checkInheritance('Bonsai.Transform') || checkInheritance('Bonsai.Transform'); - - let operatorType = {} - operatorType.type = sink ? 'sink' : source ? 'source' : transform ? 'transform' : combinator ? 'combinator' : false ; - operatorType.showWorkflow = !!operatorType.type - - return operatorType; -} \ No newline at end of file diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index b505806..0d93590 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -1,7 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -var BonsaiCommon = require('./BonsaiCommon.js') +// Define Bonsai operator types in documentation by checking for an explicit Category tag. If the class does not provide one, +// check the inheritance tree of the class. +function defineOperatorType(model){ + const checkForCategory = (category) => model.syntax?.content[0].value.includes(`[WorkflowElementCategory(ElementCategory.${category})]`); + const checkInheritance = (inheritance) => model.inheritance?.some(inherited => inherited.uid.includes(inheritance)); + + source = checkForCategory('Source') || checkInheritance('Bonsai.Source'); + sink = checkForCategory('Sink') || checkInheritance('Bonsai.Sink') || checkInheritance('Bonsai.IO.StreamSink') || checkInheritance('Bonsai.IO.FileSink'); + combinator = checkForCategory('Combinator') || checkInheritance('Bonsai.Combinator') || checkInheritance('Bonsai.WindowCombinator'); + transform = checkForCategory('Transform') || checkInheritance('Bonsai.Transform') || checkInheritance('Bonsai.Transform'); + + let operatorType = {} + operatorType.type = sink ? 'sink' : source ? 'source' : transform ? 'transform' : combinator ? 'combinator' : false ; + + return operatorType; +} // This function is important for stripping the extra line that is present in some fields // replace last instance of ' { + // Remove input if it's empty + if (!item.input.specName && !item.input.description) { + delete item.input; + } + return item; + }); return overloads; } -// compile list of properties -function defineProperties(model){ - properties = []; - if (model.children){ - const childrenLength = model.children.length; - for (let i = 0; i < childrenLength; i++){ - if (model.children[i].type === 'property'){ - - // This section adds enum fields and values to the property table if the property is an enum - // However doesnt always work (In Pulsepal Repo - Outputchannel enum doesnt show sometimes but the others do) - // Bug present in original template so need to troubleshoot - // Nice to have I think but not critical. - potentialEnumYml = '~/api/' + model['children'][i].syntax.return.type.uid + '.yml'; - let enumFields = []; - if (model['__global']['_shared'][potentialEnumYml] && (model['__global']['_shared'][potentialEnumYml]['type'] === 'enum')){ - enumFields = defineEnumFields(model['__global']['_shared'][potentialEnumYml]); - } - if (enumFields.length > 0){ - properties.push({ - 'name': model.children[i].name[0].value, - 'type': model.children[i].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([model.children[i].summary, model.children[i].remarks].join('')), - 'enumFields': enumFields, - 'hasEnum': true - }); - } - // This adds the rest of the non-enum properties normally - else { - properties.push({ - 'name': model.children[i].name[0].value, - 'type': model.children[i].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([model.children[i].summary, model.children[i].remarks].join('')) - }); - } - } +// extracts enums so that they can be expanded in the properties table +function processChildProperty(child, sharedModel) { + const enumFields = sharedModel[`~/api/${child.syntax.return.type.uid}.yml`]?.type === 'enum' ? + extractEnumData(sharedModel[`~/api/${child.syntax.return.type.uid}.yml`]) : + []; + return { + 'name': child.name[0].value, + 'type': child.syntax.return.type.specName[0].value, + 'propertyDescription': { + 'text': enumFields.length > 0 + ? [child.summary, child.remarks].join('') + : removeBottomMargin([child.summary, child.remarks].join('')), + 'hasEnum': enumFields.length > 0, + 'enum': enumFields, } } - // This adds properties that belong to the members that it inherits (and which show up in the Bonsai side panel) - // On a default docfx website they dont show, so its pretty important. - if (model.inheritedMembers){ - const inheritedMembersLength = model.inheritedMembers.length; - for (let i = 0; i < inheritedMembersLength; i++){ - if (model.inheritedMembers[i].type && (model.inheritedMembers[i].type === 'property')){ - let inheritedMemberYml = '~/api/' + model.inheritedMembers[i].parent + '.yml'; - if (model['__global']['_shared'][inheritedMemberYml]['children']){ - let inheritedMemberChildrenLength = model['__global']['_shared'][inheritedMemberYml]['children'].length; - for (let j = 0; j < inheritedMemberChildrenLength; j++){ - if (model.inheritedMembers[i].uid === model['__global']['_shared'][inheritedMemberYml]['children'][j].uid){ - properties.push( - {'name': model.inheritedMembers[i].name[0].value, - 'type': model['__global']['_shared'][inheritedMemberYml]['children'][j].syntax.return.type.specName[0].value, - 'description': removeBottomMargin([model['__global']['_shared'][inheritedMemberYml]['children'][j].summary, - model['__global']['_shared'][inheritedMemberYml]['children'][j].remarks].join('')) - }); - } - } - } - } - } - } - return properties; } +function extractPropertiesData(model, sharedModel) { + return model?.children + .filter(child => child.type === 'property' && child.syntax) + .map(child => processChildProperty(child, sharedModel)); +} + +function extractPropertiesFromInheritedMembersData(model, sharedModel) { + return model.inheritedMembers + .filter(inheritedMember => inheritedMember.type === 'property') + .map(inheritedMember => { + return processChildProperty( + sharedModel[`~/api/${inheritedMember.parent}.yml`].children.find(inheritedMemberChild => inheritedMemberChild.uid === inheritedMember.uid), + sharedModel + ); + }); +} + + // Properties are usually already listed in declaration order which mirrors Bonsai UI. // However a bug in docfx messes up properties that have a numeric endvalue ie Device10 < Device2 // and this function fixes that. -function sortProperties(properties) { +function sortPropertiesData(properties) { return properties.sort((a, b) => { const regex = /\D+|\d+$/g; @@ -137,7 +132,7 @@ function sortProperties(properties) { // While enum fields can be accessed directly using the mustache template, this function is // still important for stripping the extra line that is present in the summary/remarks field -function defineEnumFields(model){ +function extractEnumData(model){ return model.children .filter(child => child.type === 'field') .map(child => ({ @@ -155,33 +150,30 @@ exports.preTransform = function (model) { model.bonsai.description = [model.summary, model.remarks].join(''); - operatorType = BonsaiCommon.defineOperatorType(model); + operatorType = defineOperatorType(model); if (operatorType.type){ model.bonsai.operatorType = operatorType.type; - } - - if (operatorType.showWorkflow) { - model.bonsai.showWorkflow = operatorType.showWorkflow; - } - - operators = defineInputsAndOutputs(model); - if (operators.length > 0){ + model.bonsai.showWorkflow = true + operators = defineInputsAndOutputs(model); model.bonsai.operators = operators; } - properties = defineProperties(model); - if (properties.length > 0){ - model.bonsai.hasProperties = true; - model.bonsai.properties = sortProperties(properties); + if (model.type === 'class') { + properties = sortPropertiesData([ + ...extractPropertiesData(model, model.__global._shared), + ...extractPropertiesFromInheritedMembersData(model, model.__global._shared), + ]); + if (properties.length > 0){ + model.bonsai.hasProperties = true; + model.bonsai.properties = properties + } } - enumFields = defineEnumFields(model); - if (enumFields.length > 0){ + else if (model.type === 'enum') { + model.bonsai.enumFields = extractEnumData(model); model.bonsai.hasEnumFields = true; - model.bonsai.enumFields = enumFields; } - return model; } diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index 965ea0e..b8fcdb3 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -1,3 +1,5 @@ + + {{#isClass}}
diff --git a/template/api/partials/enum.tmpl.partial b/template/api/partials/enum.tmpl.partial index f2b2e4d..4755efe 100644 --- a/template/api/partials/enum.tmpl.partial +++ b/template/api/partials/enum.tmpl.partial @@ -26,7 +26,7 @@ - {{{description}}} + {{{enumDescription}}} {{/bonsai.enumFields}} diff --git a/template/api/partials/propertyTables.tmpl.partial b/template/api/partials/propertyTables.tmpl.partial index fe8b055..bd47d08 100644 --- a/template/api/partials/propertyTables.tmpl.partial +++ b/template/api/partials/propertyTables.tmpl.partial @@ -9,18 +9,21 @@ - {{{description}}} - - {{#hasEnum}} -
- - {{#enumFields}} -
{{{field&value}}}
-
{{{description}}}
- {{/enumFields}} - -
- {{/hasEnum}} - +
+ {{#propertyDescription}} + {{{propertyDescription.text}}} + {{#hasEnum}} + + {{#enum}} + + + + + {{/enum}} +
{{{field&value}}}{{{enumDescription}}}
+ {{/hasEnum}} + {{/propertyDescription}} +
+ \ No newline at end of file diff --git a/template/api/styles/styles.css b/template/api/styles/styles.css new file mode 100644 index 0000000..0598798 --- /dev/null +++ b/template/api/styles/styles.css @@ -0,0 +1,35 @@ +div.tableFormat *:last-child { + margin-bottom: 0; + } + + div.tableFormat table { + display: grid; + grid-template-columns: auto; + margin-top: 1rem; + margin: 0; + padding: 0; + border: 0 hidden; + border-collapse: collapse; + } + + div.tableFormat td { + padding: 0; + border: 0 hidden; + } + + div.tableFormat td.term { + /* !important tag prevents overrides from dotnet.css associated with: + body[data-yaml-mime="ManagedReference"] article td.term, body[data-yaml-mime="ApiPage"] article td.term + important tags not good practice*/ + font-weight: var(--bs-body-font-weight) !important; + white-space: nowrap; + } + + div.tableFormat td.description { + padding-left: 1rem; + } + + .quick-links > .table-responsive > table.table.table-bordered.table-condensed { + border: 0px hidden transparent; + } + \ No newline at end of file From a86183449b1a9709fd81e3e700f1a57de217be29 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 22 Aug 2024 15:03:31 -0700 Subject: [PATCH 24/29] Surface links to Bonsai docs for observables and operators --- template/api/ManagedReference.extension.js | 7 ++++--- template/api/partials/class.tmpl.partial | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js index 0d93590..6f43f52 100644 --- a/template/api/ManagedReference.extension.js +++ b/template/api/ManagedReference.extension.js @@ -29,18 +29,19 @@ function removeBottomMargin(str) { // Strip IObservable and replace 'TSource' with 'Anything' // Added a null check to return an empty string to avoid undefined errors in new refactored code -// Consider replace "Anything" with "Observable" or "Any Observable" with a link to the observable guide +// Added links to Bonsai user guide on operators function replaceIObservableAndTSource(str){ + const observableLink = 'Observable' if (!str) { return ''; } else if (str.includes('IGroupedObservable')){ const re = new RegExp(' {{#bonsai.operatorType}}

- {{bonsai.operatorType}} Operator + {{bonsai.operatorType}} Operator

{{/bonsai.operatorType}}
From 3000e2171c87fcfb33f4ccd6d3bd836078d17900 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 22 Aug 2024 15:12:50 -0700 Subject: [PATCH 25/29] Remove constructors from API pages --- template/api/partials/class.tmpl.partial | 26 ------------------------ 1 file changed, 26 deletions(-) diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial index 8da7b84..006577b 100644 --- a/template/api/partials/class.tmpl.partial +++ b/template/api/partials/class.tmpl.partial @@ -47,32 +47,6 @@ {{/bonsai.hasProperties}} -{{#children}} -{{#inConstructor}} -{{#children}} -

Constructors

- - - - - - - - - - -
ConstructorsParameters
- {{{specName.0.value}}}{{{summary}}} - - {{#syntax.parameters}} - {{{type.specName.0.value}}}{{{description}}} - {{/syntax.parameters}} -
- -{{/children}} -{{/inConstructor}} -{{/children}} -

Relationships

{{__global.namespace}} - {{{namespace.specName.0.value}}}
From 74dbb7a2aeb3ecc77f79ca1bc7ee6421baa81f7e Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 22 Aug 2024 16:33:34 -0700 Subject: [PATCH 26/29] Update readme with installation instructions --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e00eb49..42cb2c3 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,22 @@ # docfx-tools -A docfx template for package documentation, patching the modern template to provide stylesheets and scripts for rendering custom workflow containers with copy functionality. +A repository of docfx tools for Bonsai package documentation: +- Docfx Workflow Container template patching the modern template to provide stylesheets and scripts for rendering custom workflow containers with copy functionality. +- Docfx API TOC template that groups nodes by operator type in the table of contents(TOC) on API pages. +- Docfx API template that revamps the API page to enhance user-friendliness +- Powershell Scripts that automate several content generation steps for package documentation websites. -## How to use +## How to include -To include this template in a docfx website, first clone this repository as a submodule: +To include this repo in a docfx website, first clone this repository as a submodule: ``` git submodule add https://github.com/bonsai-rx/docfx-tools bonsai ``` -Then modify `docfx.json` to include the template immediately after the modern template: +## Using Workflow Container Template + +Modify `docfx.json` to include the template immediately after the modern template: ```json "template": [ @@ -38,12 +44,45 @@ export default { } } ``` +## Using API TOC Template and API template + +Currently these two templates are bundled together, as the API TOC template relies on an extension that is used by the API template. + +For the API TOC template especially, the local installation of docfx needs to be updated to >= v2.77.0. + +```ps1 +dotnet tool update docfx +``` -## Powershell Scripts +Modify `docfx.json` to include the api template in the template section (note both the workflow container and API TOC template have to be added separately). -This repository also provides helper scripts to automate several content generation steps for package documentation websites. +```json +"template": [ + "default", + "modern", + "bonsai/template", + "bonsai/template/api", + "template" +] +``` +In addition, the images and custom css styles need to be added to the resources section. + +```json +"resource": [ + { + "files": [ + "logo.svg", + "favicon.ico", + "images/**", + "workflows/**", + "bonsai/template/api/images/**", + "bonsai/template/api/styles/**" + ] + } +] +``` -### Exporting workflow images +## Powershell Scripts - Exporting workflow images Exporting SVG images for all example workflows can be automated by placing all `.bonsai` files in a `workflows` folder and calling the below script pointing to the bin directory to include. A bonsai environment is assumed to be available in the `.bonsai` folder in the repository root. From 5ee6e60cf8357e2110e7500fed451907f8d7393f Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 22 Aug 2024 16:49:22 -0700 Subject: [PATCH 27/29] Update README with instructions for operator workflow containers --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 42cb2c3..e7f9cba 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A repository of docfx tools for Bonsai package documentation: - Docfx Workflow Container template patching the modern template to provide stylesheets and scripts for rendering custom workflow containers with copy functionality. - Docfx API TOC template that groups nodes by operator type in the table of contents(TOC) on API pages. -- Docfx API template that revamps the API page to enhance user-friendliness +- Docfx API template that revamps the API page to enhance user-friendliness. - Powershell Scripts that automate several content generation steps for package documentation websites. ## How to include @@ -81,6 +81,8 @@ In addition, the images and custom css styles need to be added to the resources } ] ``` +To add individual operator workflows for the API pages, open Bonsai, add the operator, and save each individual operator workflow as `OperatorName.bonsai` (case sensitive) in `docs/workflows/operators`. + ## Powershell Scripts - Exporting workflow images From 968ca4a5427a9cb5c4e1081680d38beead2d0fbd Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Fri, 23 Aug 2024 15:41:05 -0700 Subject: [PATCH 28/29] Update README after decoupling API TOC from API template --- README.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e7f9cba..d0ecacf 100644 --- a/README.md +++ b/README.md @@ -44,17 +44,9 @@ export default { } } ``` -## Using API TOC Template and API template +## Using API template -Currently these two templates are bundled together, as the API TOC template relies on an extension that is used by the API template. - -For the API TOC template especially, the local installation of docfx needs to be updated to >= v2.77.0. - -```ps1 -dotnet tool update docfx -``` - -Modify `docfx.json` to include the api template in the template section (note both the workflow container and API TOC template have to be added separately). +Modify `docfx.json` to include the api template in the template section (note both the workflow container and API template have to be added separately). ```json "template": [ From 0f97d2e34cb2c360e5612f3be20fc0624dc16dcc Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Sat, 21 Sep 2024 23:34:32 -0700 Subject: [PATCH 29/29] Refactor IO diagram, reduce size --- template/api/partials/diagram.tmpl.partial | 53 ++++++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/template/api/partials/diagram.tmpl.partial b/template/api/partials/diagram.tmpl.partial index 915b6c1..e2cb8aa 100644 --- a/template/api/partials/diagram.tmpl.partial +++ b/template/api/partials/diagram.tmpl.partial @@ -1,21 +1,54 @@ {{#bonsai.operators}} + +
{{{description}}}
- +
-
- +
+ {{#input}} - - {{/input}} @@ -25,19 +58,19 @@ - -
+
{{{specName}}}
{{{description}}}
+ right-arrow + representation of a source, sink, transform or combinator operator - +
+ - -
+ right-arrow +
{{{output.specName}}}
{{{output.description}}}