Skip to content

Instantly share code, notes, and snippets.

@phillipharding
Last active September 22, 2020 23:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phillipharding/64575fe195a5590a42df536043254628 to your computer and use it in GitHub Desktop.
Save phillipharding/64575fe195a5590a42df536043254628 to your computer and use it in GitHub Desktop.
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