Last active
September 22, 2020 23:55
-
-
Save phillipharding/64575fe195a5590a42df536043254628 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { sp } from "@pnp/sp/presets/all"; | |
import "@pnp/sp/taxonomy"; | |
import { taxonomy, ITerm, ITermData } from "@pnp/sp-taxonomy" | |
(async () => { | |
interface ITermDataNode { | |
Id: string; | |
ParentTermId?: string; | |
Name: string; | |
Path: string; | |
Description: string; | |
Term: ITerm & ITermData; | |
Children: ITermDataNode[]; | |
IsTopLevel?: boolean; | |
}; | |
const getTermAncestorHierarchy = async (termId: string): Promise<ITermDataNode[]> => { | |
let hierarchy: ITermDataNode[] = []; | |
const term = await termset.getTermById(termId).get(); | |
if (term) { | |
term.Id = term.Id.replace(/^\/Guid\(|\)\/$/gi, ""); | |
console.debug(`traverseTermPath::> ${term.Name} :: ${term.PathOfTerm}`); | |
const parentTerm = await term.parent.get(); | |
if (parentTerm && (typeof parentTerm["Id"] !== "undefined") && (parentTerm.Id)) { | |
parentTerm.Id = parentTerm.Id.replace(/^\/Guid\(|\)\/$/gi, ""); | |
hierarchy.splice(0, 0, ...(await getTermAncestorHierarchy(parentTerm.Id))); | |
} | |
hierarchy.push({ Name: term.Name, Id: term.Id, Path: term.PathOfTerm, Description: term.Description, Term: term, Children: [], | |
IsTopLevel: (term.PathOfTerm || "").indexOf(";") === -1 | |
}); | |
} | |
return hierarchy; | |
}; | |
const getTermDescendantHierarchy = async (termId: string, term?: ITermData & ITerm): Promise<ITermDataNode> => { | |
let hierarchy: ITermDataNode = null; | |
let thisTerm: ITermData & ITerm; | |
if (((term === null) || (typeof term === "undefined"))) { | |
thisTerm = await termset.getTermById(termId).get(); | |
} else { | |
thisTerm = term; | |
} | |
if (thisTerm) { | |
hierarchy = { Name: thisTerm.Name, Id: thisTerm.Id.replace(/^\/Guid\(|\)\/$/gi, ""), Path: thisTerm.PathOfTerm, Description: thisTerm.Description, Term: thisTerm, Children: [], IsTopLevel: (thisTerm.PathOfTerm || "").indexOf(";") === -1 }; | |
const childTerms = (await thisTerm.terms.get()) || []; | |
for (let cidx = 0; cidx < childTerms.length; cidx++) { | |
const cTerm = childTerms[cidx]; | |
const cTermId = cTerm.Id.replace(/^\/Guid\(|\)\/$/gi, ""); | |
const childTerm = await getTermDescendantHierarchy(cTermId, cTerm); | |
if (childTerm) { | |
hierarchy.Children.push(childTerm); | |
} | |
} | |
} | |
return hierarchy; | |
} | |
const getTermsetTopLevelTerms = async (termsetId: string): Promise<ITermDataNode[]> => { | |
let hierarchy: ITermDataNode[] = []; | |
const allTerms = await termset.terms.get(); | |
hierarchy = allTerms | |
.filter((term: ITerm & ITermData) => (term.PathOfTerm || "").indexOf(";") === -1) | |
.map((term: ITerm & ITermData) => { | |
return { | |
Id: term.Id.replace(/^\/Guid\(|\)\/$/gi, ""), | |
Name: term.Name, | |
Path: term.PathOfTerm, | |
Description: term.Description, | |
Term: term, | |
Children: [], | |
IsTopLevel: (term.PathOfTerm || "").indexOf(";") === -1 | |
}; | |
}); | |
return hierarchy; | |
}; | |
const buildHierarchyFromFlatTermList = (termArray: ITermDataNode[]): ITermDataNode[] => { | |
let nodeTree = { | |
Children: [], | |
}; | |
/** iterate each term */ | |
for (let idx = 0; idx < termArray.length; idx++) { | |
let currentTerm = termArray[idx]; | |
let currentTermPath = currentTerm.Path.split(';'); | |
let currentChildNodes = nodeTree.Children; | |
let parentNodeId = ""; | |
/* iterate each segment of the current terms path */ | |
for (var i = 0; i < currentTermPath.length; i++) { | |
let foundNode = false; | |
/* find this node in the current set of childNodes */ | |
let findNodeIndex = -1; | |
for (let z = 0; z < currentChildNodes.length; z++) { | |
if (currentChildNodes[z].Name === currentTermPath[i]) { | |
foundNode = true; | |
findNodeIndex = z; | |
parentNodeId = currentChildNodes[z].Id; | |
break; | |
} | |
} | |
/* select the child node for the current term path, OR, create a new one */ | |
let termNode = foundNode | |
? currentChildNodes[findNodeIndex] | |
: { | |
Name: currentTermPath[i], | |
Children: [] | |
}; | |
/* if we're the last term path segment, add the term properties */ | |
if (i === currentTermPath.length - 1) { | |
termNode.Id = currentTerm.Id; | |
termNode.ParentTermId = currentTerm.ParentTermId || parentNodeId; | |
termNode.Name = currentTerm.Name; | |
termNode.Path = currentTerm.Path; | |
termNode.Description = currentTerm.Description; | |
termNode.Term = currentTerm.Term; | |
termNode.IsTopLevel = currentTerm.IsTopLevel; | |
} | |
/* if there was a termnode for the current term path, set the current childNodes as that termNodes child nodes for the next term path iteration */ | |
if (foundNode) { | |
currentChildNodes = termNode.Children; | |
} else { | |
/* we created a new termNode for the current term path, add it to the current set of Children */ | |
currentChildNodes.push(termNode); | |
/* if this term path is not the last, set the current childNodes as that termNodes child nodes for the next term path iteration */ | |
if (i !== currentTermPath.length - 1) { | |
currentChildNodes = termNode.Children; | |
} | |
} | |
} | |
} | |
return nodeTree.Children || []; | |
} | |
const getAllTerms = async (includeParentTermIds: boolean): Promise<ITermDataNode[]> => { | |
let hierarchy: ITermDataNode[] = []; | |
const allTerms = await termset.terms.select().get(); | |
if (includeParentTermIds) { | |
for( let cidx = 0; cidx < allTerms.length; cidx++ ) { | |
const cTerm = allTerms[cidx]; | |
const cParentTerm = await cTerm.parent.get(); | |
if (cParentTerm && (typeof cParentTerm["Id"] !== "undefined") && (cParentTerm.Id)) { | |
cParentTerm.Id = cParentTerm.Id.replace(/^\/Guid\(|\)\/$/gi, ""); | |
} | |
hierarchy.push({ | |
Id: cTerm.Id.replace(/^\/Guid\(|\)\/$/gi, ""), | |
Name: cTerm.Name, | |
Path: cTerm.PathOfTerm, | |
Description: cTerm.Description, | |
Term: cTerm, | |
Children: [], | |
IsTopLevel: (cTerm.PathOfTerm || "").indexOf(";") === -1, | |
ParentTermId: cParentTerm ? `${cParentTerm.Id || ""}` : "" | |
}); | |
} | |
} else { | |
hierarchy = allTerms.map((term: ITerm & ITermData) => { | |
return { | |
Id: term.Id.replace(/^\/Guid\(|\)\/$/gi, ""), | |
Name: term.Name, | |
Path: term.PathOfTerm, | |
Description: term.Description, | |
Term: term, | |
Children: [], | |
IsTopLevel: (term.PathOfTerm || "").indexOf(";") === -1 | |
}; | |
}); | |
} | |
hierarchy.sort((a: any, b: any) => { | |
return (a.Path.toLowerCase() < b.Path.toLowerCase()) ? -1 : | |
(a.Path.toLowerCase() > b.Path.toLowerCase()) ? 1 : | |
0; | |
}); | |
return hierarchy; | |
}; | |
const ts = await taxonomy.termStores.get(); | |
console.log(ts); | |
const termstore = (await taxonomy.termStores.get())[0]; | |
const termset = await termstore.getTermSetsByName("Council Service Area", termstore.DefaultLanguage).getByName("Council Service Area").get(); | |
console.debug(termset); | |
let allTerms = await getAllTerms(false); | |
console.debug("All Terms: ", allTerms); | |
const topLevelTerms = await getTermsetTopLevelTerms(termset.Id); | |
console.debug("Top Level Terms: ", topLevelTerms); | |
for (let idx = 0; idx < topLevelTerms.length; idx++) { | |
const tlTerm = topLevelTerms[idx]; | |
console.debug(`Top LevelTerm: ${tlTerm.Name} [${tlTerm.Path}]`); | |
} | |
let path = await getTermAncestorHierarchy("a9e84178-d021-4057-b42c-218308a7d3f0"); | |
console.debug("Ancestor Hierarchy: ", path); | |
path = await getTermAncestorHierarchy("118a0552-67fe-4d8e-afae-660ee83ebb02"); | |
console.debug("Ancestor Hierarchy: ", path); | |
const CDSTopLevelTermId = "a547dc2b-0844-44be-b70a-ff3fb6d198d8"; | |
let hierarchy = await getTermDescendantHierarchy(CDSTopLevelTermId); | |
console.debug(`Descendant Hierarchy (${CDSTopLevelTermId}): `, hierarchy); | |
const allTermsHierarchy = buildHierarchyFromFlatTermList(allTerms); | |
console.debug(`All Terms Hierarchy: `, allTermsHierarchy); | |
})().catch(console.log); | |
console.clear(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment