From 138ce432e208e1c17120c3a1eb5c76018beffc0e Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Thu, 8 Aug 2024 14:15:56 -0700 Subject: [PATCH 01/11] 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 144b92f39d4713c68d169662d5f5855a8c978e16 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Sun, 11 Aug 2024 16:48:32 -0700 Subject: [PATCH 02/11] Modify TOC to display Bonsai categories Refactor defineSubOperators function into new BonsaiCommon.js file so it can be used by ManagedReference and TOC templates Modify TOC logic and categories in toc.extension.js --- template/api/BonsaiCommon.js | 44 +++++++++++ template/api/ManagedReference.extension.js | 47 +---------- template/api/toc.extension.js | 90 +++++++++++----------- 3 files changed, 90 insertions(+), 91 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..c3ebd99 --- /dev/null +++ b/template/api/BonsaiCommon.js @@ -0,0 +1,44 @@ +// 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. + +exports.defineOperatorType = 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; + } + 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: Sun, 11 Aug 2024 21:35:43 -0700 Subject: [PATCH 03/11] Update TOC categories to include Transforms - Add Transforms identification logic to defineOperatorType function in BonsaiCommon.js - Strip OE operator specific code from defineOperatorType - Add in unique Bonsai combinators, sinks and transform that were missing from defineOperatorType - Update TOC categories in toc extension.js --- template/api/BonsaiCommon.js | 41 +++++++++++++++++++++++------------ template/api/toc.extension.js | 15 ++++++++----- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/template/api/BonsaiCommon.js b/template/api/BonsaiCommon.js index c3ebd99..4fd8f62 100644 --- a/template/api/BonsaiCommon.js +++ b/template/api/BonsaiCommon.js @@ -1,44 +1,57 @@ -// 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. +// 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. Ignore Bonsai.Combinator if Bonsai.Sink or Bonsai.Transform is present as many +// sink and transform operators inherit Bonsai.Combinator exports.defineOperatorType = function defineOperatorType(model){ - let operatorType = {'source': false, 'sink': false, 'combinator': false}; + 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.Combinator)]')){ - operatorType.combinator = true; + else if (model.syntax.content[0].value.includes('[WorkflowElementCategory(ElementCategory.Transform)]')){ + operatorType.transform = true; } } - if (!(operatorType.source || operatorType.sink || operatorType.combinator)){ + if (!(operatorType.source || operatorType.combinator || operatorType.sink || operatorType.transform)){ 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.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.Combinator')){ + else if (model.inheritance[i].uid.includes('Bonsai.Transform')){ + operatorType.combinator = false; + operatorType.transform = true; + } + else if (model.inheritance[i].uid.includes('Bonsai.WindowCombinator')){ operatorType.combinator = true; } - if (model.inheritance[i].uid.includes('OpenEphys.Onix1.MultiDeviceFactory')){ - operatorType.hub = 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('OpenEphys.Onix1.SingleDeviceFactory')){ - operatorType.device = true; + else if (model.inheritance[i].uid.includes('Bonsai.Dsp.ArrayTransform')){ + operatorType.transform = true; } } } } - operatorType.showWorkflow = operatorType.source | operatorType.sink | operatorType.combinator; + operatorType.showWorkflow = operatorType.source | operatorType.combinator | operatorType.sink | operatorType.transform; return operatorType; } diff --git a/template/api/toc.extension.js b/template/api/toc.extension.js index a7e35e2..c84e04f 100644 --- a/template/api/toc.extension.js +++ b/template/api/toc.extension.js @@ -21,7 +21,9 @@ exports.preTransform = function (model) { //setups operator categories //TODO check if any of the items is empty and remove them let items = [{ - 'name': 'Source', + 'name': 'Sources', + 'items': []}, { + 'name': 'Transforms', 'items': []}, { 'name': 'Sinks', 'items': []}, { @@ -41,18 +43,21 @@ exports.preTransform = function (model) { if (operatorType.source){ items[0].items.push(namespace.items[i]); } - else if (operatorType.sink){ + else if (operatorType.transform){ items[1].items.push(namespace.items[i]); } - else if (operatorType.combinator){ + else if (operatorType.sink){ items[2].items.push(namespace.items[i]); } - else { + else if (operatorType.combinator){ items[3].items.push(namespace.items[i]); } + else { + items[4].items.push(namespace.items[i]); + } } if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'enum'){ - items[4].items.push(namespace.items[i]); + items[5].items.push(namespace.items[i]); } } namespace.items = items; From a01784bddcf2e199dd3266b6361f86ea046684fe Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Sun, 11 Aug 2024 21:44:41 -0700 Subject: [PATCH 04/11] Filter TOC to remove empty categories --- template/api/toc.extension.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/api/toc.extension.js b/template/api/toc.extension.js index c84e04f..ca889cf 100644 --- a/template/api/toc.extension.js +++ b/template/api/toc.extension.js @@ -19,7 +19,6 @@ exports.preTransform = function (model) { itemsItemsLength = namespace.items.length; //setups operator categories - //TODO check if any of the items is empty and remove them let items = [{ 'name': 'Sources', 'items': []}, { @@ -60,6 +59,7 @@ exports.preTransform = function (model) { items[5].items.push(namespace.items[i]); } } + items = items.filter(item => item.items.length > 0); namespace.items = items; } } From 023fd90feecb67d6e1172080a126ca17cb0d3ec8 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Mon, 12 Aug 2024 11:27:04 -0700 Subject: [PATCH 05/11] Update comments --- template/api/BonsaiCommon.js | 13 ++++++++++--- template/api/toc.extension.js | 14 +++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/template/api/BonsaiCommon.js b/template/api/BonsaiCommon.js index 4fd8f62..9eb4ebf 100644 --- a/template/api/BonsaiCommon.js +++ b/template/api/BonsaiCommon.js @@ -1,8 +1,8 @@ -// 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. Ignore Bonsai.Combinator if Bonsai.Sink or Bonsai.Transform is present as many -// sink and transform operators inherit Bonsai.Combinator +// 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)]')){ @@ -22,6 +22,9 @@ exports.defineOperatorType = function defineOperatorType(model){ 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; } @@ -36,6 +39,8 @@ exports.defineOperatorType = function defineOperatorType(model){ 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; } @@ -51,6 +56,8 @@ exports.defineOperatorType = function defineOperatorType(model){ } } } + + // 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/toc.extension.js b/template/api/toc.extension.js index ca889cf..6f908c6 100644 --- a/template/api/toc.extension.js +++ b/template/api/toc.extension.js @@ -8,17 +8,15 @@ var BonsaiCommon = require('./BonsaiCommon.js') */ exports.preTransform = function (model) { - //checks and applies TOC customisation only to API page + // Checks and applies TOC customisation only to API page if (model._key === 'api/toc.yml') { - //iterates through each namespace for packages with multiple namespaces + // Iterates through each namespace for packages with multiple namespaces for (namespace of model.items) { - - //not sure if this check is really necessary are there empty namespaces? if (namespace.items) { itemsItemsLength = namespace.items.length; - - //setups operator categories + + // Setups operator categories let items = [{ 'name': 'Sources', 'items': []}, { @@ -34,7 +32,7 @@ exports.preTransform = function (model) { 'items': [] }]; - // iterates through each item in the namespace and sorts them into categories + // Iterates through each item in the namespace and sorts them into categories for (let i = 0; i < itemsItemsLength; i++) { globalYml = '~/api/' + namespace.items[i].topicUid + '.yml'; if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'class'){ @@ -59,6 +57,8 @@ exports.preTransform = function (model) { items[5].items.push(namespace.items[i]); } } + + // Filters out empty TOC categories and sets namespace TOC items items = items.filter(item => item.items.length > 0); namespace.items = items; } From 5e1aea89226b3054a83d6f04726dc61433bd2ee9 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Mon, 12 Aug 2024 11:31:23 -0700 Subject: [PATCH 06/11] Strip template engine files not required for TOC --- template/api/ManagedReference.extension.js | 581 ------------------ .../api/ManagedReference.html.primary.tmpl | 7 - 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 -- 7 files changed, 926 deletions(-) delete mode 100644 template/api/ManagedReference.extension.js delete mode 100644 template/api/ManagedReference.html.primary.tmpl delete mode 100644 template/api/conceptual.html.primary.tmpl delete mode 100644 template/api/partials/class.tmpl.partial delete mode 100644 template/api/partials/diagram.tmpl.partial delete mode 100644 template/api/partials/enum.tmpl.partial delete mode 100644 template/api/partials/propertyTables.tmpl.partial diff --git a/template/api/ManagedReference.extension.js b/template/api/ManagedReference.extension.js deleted file mode 100644 index 2f930d3..0000000 --- a/template/api/ManagedReference.extension.js +++ /dev/null @@ -1,581 +0,0 @@ -// 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( ' 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; -} - -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 = BonsaiCommon.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 deleted file mode 100644 index 5f4ab4f..0000000 --- a/template/api/ManagedReference.html.primary.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -{{!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/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 diff --git a/template/api/partials/class.tmpl.partial b/template/api/partials/class.tmpl.partial deleted file mode 100644 index 0e25a93..0000000 --- a/template/api/partials/class.tmpl.partial +++ /dev/null @@ -1,109 +0,0 @@ -{{#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 deleted file mode 100644 index c87f104..0000000 --- a/template/api/partials/diagram.tmpl.partial +++ /dev/null @@ -1,114 +0,0 @@ -{{#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 deleted file mode 100644 index 66b28c6..0000000 --- a/template/api/partials/enum.tmpl.partial +++ /dev/null @@ -1,38 +0,0 @@ -{{#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 deleted file mode 100644 index 84d3b9e..0000000 --- a/template/api/partials/propertyTables.tmpl.partial +++ /dev/null @@ -1,37 +0,0 @@ - - - - - {{{name}}} - - - - - - {{{type}}} - - - - - - {{{description}}} - - {{#hasEnum}} - -
- - {{#enumFields}} - -
{{{field&value}}}
- -
{{{description}}}
- - {{/enumFields}} - -
- - {{/hasEnum}} - - - - \ No newline at end of file From 3f4298ca884bc53d1e08e6b264b452d4b694d516 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Tue, 13 Aug 2024 16:23:17 -0700 Subject: [PATCH 07/11] Update README with usage instructions --- README.md | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e00eb49..88b3b5a 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,21 @@ # 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. +- 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 +43,27 @@ export default { } } ``` +## Using API TOC Template + +The local installation of docfx needs to be updated to >= v2.77.0. -## Powershell Scripts +```ps1 +dotnet tool update docfx +``` -This repository also provides helper scripts to automate several content generation steps for package documentation websites. +Modify `docfx.json` to include the api template (note both the workflow container and API TOC template have to be added separately). + +```json +"template": [ + "default", + "modern", + "bonsai/template", + "bonsai/template/api", + "template" +] +``` -### 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 7e95714c9a4886f282eaebd4dc022a9501e8edc0 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Fri, 16 Aug 2024 17:13:07 -0700 Subject: [PATCH 08/11] Refactored defineOperatorType code and TOC logic Co-authored-by: Cris --- template/api/BonsaiCommon.js | 63 ++++++----------------------------- template/api/toc.extension.js | 25 +++++++------- 2 files changed, 23 insertions(+), 65 deletions(-) diff --git a/template/api/BonsaiCommon.js b/template/api/BonsaiCommon.js index 9eb4ebf..152fdb0 100644 --- a/template/api/BonsaiCommon.js +++ b/template/api/BonsaiCommon.js @@ -3,62 +3,19 @@ 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; - } + 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'); + + let operatorType = {} + operatorType.type = sink ? 'sink' : source ? 'source' : transform ? 'transform' : combinator ? 'combinator' : false ; + operatorType.showWorkflow = !!operatorType.type - // 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/toc.extension.js b/template/api/toc.extension.js index 6f908c6..beacdfa 100644 --- a/template/api/toc.extension.js +++ b/template/api/toc.extension.js @@ -11,6 +11,14 @@ exports.preTransform = function (model) { // Checks and applies TOC customisation only to API page if (model._key === 'api/toc.yml') { + //Setups operator mapping + const typeIndexMap = { + 'source': 0, + 'transform': 1, + 'sink': 2, + 'combinator': 3 + }; + // Iterates through each namespace for packages with multiple namespaces for (namespace of model.items) { if (namespace.items) { @@ -37,18 +45,11 @@ exports.preTransform = function (model) { globalYml = '~/api/' + namespace.items[i].topicUid + '.yml'; if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'class'){ operatorType = BonsaiCommon.defineOperatorType(model.__global._shared[globalYml]); - if (operatorType.source){ - items[0].items.push(namespace.items[i]); - } - else if (operatorType.transform){ - items[1].items.push(namespace.items[i]); - } - else if (operatorType.sink){ - items[2].items.push(namespace.items[i]); - } - else if (operatorType.combinator){ - items[3].items.push(namespace.items[i]); - } + + const index = typeIndexMap[operatorType.type] + if (index !== undefined) { + items[index].items.push(namespace.items[i]); + } else { items[4].items.push(namespace.items[i]); } From be8356928de873c3392dab0744a22bbcea815f90 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Wed, 21 Aug 2024 22:42:21 -0700 Subject: [PATCH 09/11] Remove BonsaiCommon.js - as this file ended up only containing one function, it was removed and the function integrated into toc.extension.js --- template/api/BonsaiCommon.js | 21 --------------------- template/api/toc.extension.js | 20 ++++++++++++++++++-- 2 files changed, 18 insertions(+), 23 deletions(-) delete mode 100644 template/api/BonsaiCommon.js diff --git a/template/api/BonsaiCommon.js b/template/api/BonsaiCommon.js deleted file mode 100644 index 152fdb0..0000000 --- a/template/api/BonsaiCommon.js +++ /dev/null @@ -1,21 +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; - } - diff --git a/template/api/toc.extension.js b/template/api/toc.extension.js index beacdfa..9424167 100644 --- a/template/api/toc.extension.js +++ b/template/api/toc.extension.js @@ -1,7 +1,23 @@ // 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 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 ; + + return operatorType; +} /** * This method will be called at the start of exports.transform in toc.html.js and toc.json.js @@ -44,7 +60,7 @@ exports.preTransform = function (model) { for (let i = 0; i < itemsItemsLength; i++) { globalYml = '~/api/' + namespace.items[i].topicUid + '.yml'; if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'class'){ - operatorType = BonsaiCommon.defineOperatorType(model.__global._shared[globalYml]); + operatorType = defineOperatorType(model.__global._shared[globalYml]); const index = typeIndexMap[operatorType.type] if (index !== undefined) { From c9bcea92d48aed6bff5ca959d4d0e122fb26c34e Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Fri, 23 Aug 2024 15:36:42 -0700 Subject: [PATCH 10/11] Decouple API TOC template from API template --- README.md | 4 ++-- template/{api => apitoc}/ManagedReference.overwrite.js | 0 template/{api => apitoc}/toc.extension.js | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename template/{api => apitoc}/ManagedReference.overwrite.js (100%) rename template/{api => apitoc}/toc.extension.js (100%) diff --git a/README.md b/README.md index 88b3b5a..a3f8cb2 100644 --- a/README.md +++ b/README.md @@ -51,14 +51,14 @@ The local installation of docfx needs to be updated to >= v2.77.0. dotnet tool update docfx ``` -Modify `docfx.json` to include the api template (note both the workflow container and API TOC template have to be added separately). +Modify `docfx.json` to include the api-toc template (note both the workflow container and API TOC template have to be added separately). ```json "template": [ "default", "modern", "bonsai/template", - "bonsai/template/api", + "bonsai/template/apitoc", "template" ] ``` diff --git a/template/api/ManagedReference.overwrite.js b/template/apitoc/ManagedReference.overwrite.js similarity index 100% rename from template/api/ManagedReference.overwrite.js rename to template/apitoc/ManagedReference.overwrite.js diff --git a/template/api/toc.extension.js b/template/apitoc/toc.extension.js similarity index 100% rename from template/api/toc.extension.js rename to template/apitoc/toc.extension.js From 30b8fa4e44c2b5954e7f78bdf96434543baa11b7 Mon Sep 17 00:00:00 2001 From: Shawn Tan Date: Sun, 12 Jan 2025 23:13:32 -0800 Subject: [PATCH 11/11] Condense Bonsai operators into one category --- template/apitoc/toc.extension.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/template/apitoc/toc.extension.js b/template/apitoc/toc.extension.js index 9424167..0a72c0c 100644 --- a/template/apitoc/toc.extension.js +++ b/template/apitoc/toc.extension.js @@ -30,9 +30,9 @@ exports.preTransform = function (model) { //Setups operator mapping const typeIndexMap = { 'source': 0, - 'transform': 1, - 'sink': 2, - 'combinator': 3 + 'transform': 0, + 'sink': 0, + 'combinator': 0 }; // Iterates through each namespace for packages with multiple namespaces @@ -42,15 +42,9 @@ exports.preTransform = function (model) { // Setups operator categories let items = [{ - 'name': 'Sources', + 'name': 'Operators', 'items': []}, { - 'name': 'Transforms', - 'items': []}, { - 'name': 'Sinks', - 'items': []}, { - 'name': 'Combinators', - 'items': []}, { - 'name': 'Helper Classes', + 'name': 'Classes', 'items': []}, { 'name': 'Enums', 'items': [] @@ -67,11 +61,11 @@ exports.preTransform = function (model) { items[index].items.push(namespace.items[i]); } else { - items[4].items.push(namespace.items[i]); + items[1].items.push(namespace.items[i]); } } if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'enum'){ - items[5].items.push(namespace.items[i]); + items[2].items.push(namespace.items[i]); } }