@Nonnull
	private CompletableFuture<Void> assemble() {
		// Ensure the AST is up-to-date before moving onto build stage.
		return parseAST().thenAccept(astResult -> {
			// If the parse finished, clear old build errors.
			if (problemTracking.removeByPhase(ProblemPhase.BUILD))
				FxThreadUtil.run(editor::redrawParagraphGraphics);

			// Skip if any problems remain in the AST
			if (!problemTracking.getProblemsByPhase(ProblemPhase.LINT).isEmpty() || lastConcreteAst == null)
				return;

			// Clear build errors since we are running the build process again.
			problemTracking.removeByPhase(ProblemPhase.BUILD);

			try {
				pipeline.assemble(lastConcreteAst, path).ifOk(result -> {
					ClassRepresentation representation = result.representation();

					lastResult = result;
					lastAssembledClassRepresentation = representation;

					if (representation instanceof JavaClassRepresentation javaClassRep) {
						// Get last class's field/method count for ensuring no duplication happened.
						// If the user changes the definition of a field/method it inserts a new one
						// instead of changing the existing declaration.
						int fieldCount = lastAssembledClass.getFields().size();
						int methodCount = lastAssembledClass.getMethods().size();

						// Update last class.
						ClassInfo assembledClass = pipeline.getClassInfo(Unchecked.cast(javaClassRep));

						// Update the local path value, this will also inform sub-components of the new content.
						// The update-lock must be set so that we don't trigger a disassembly (which would trigger an endless loop)
						updateLock.set(true);
						if (path instanceof ClassPathNode classPath) {
							// Only update if the class name was untouched.
							if (assembledClass.getName().equals(classPath.getValue().getName())) {
								ClassPathNode newPath = classPath.getParent().child(assembledClass);
								onUpdatePath(newPath);
								lastAssembledClass = assembledClass;
							} else {
								ASTElement sourceAst = lastConcreteAst.get(0);
								Error err = new Error("Changing the class name is not allowed in the assembler.\n" +
										"Use Recaf's refactoring capabilities to rename classes.", sourceAst.location());
								processErrors(List.of(err), ProblemPhase.BUILD);
							}
						} else if (path instanceof ClassMemberPathNode memberPath) {
							ClassMember oldMember = memberPath.getValue();
							ClassMember newMember;
							String memberType;
							if (oldMember.isMethod()) {
								memberType = "method";
								newMember = assembledClass.getDeclaredMethod(oldMember.getName(), oldMember.getDescriptor());
								if (methodCount != assembledClass.getMethods().size()){
									ASTElement sourceAst = lastConcreteAst.get(0);
									Error err = new Error("Assembling in this context detected a change in the number of methods.\n" +
											"Check and see if your class has illegal duplicate method definitions.", sourceAst.location());
									processErrors(List.of(err), ProblemPhase.BUILD);
								}
							} else {
								memberType = "field";
								newMember = assembledClass.getDeclaredField(oldMember.getName(), oldMember.getDescriptor());
								if (fieldCount != assembledClass.getFields().size()){
									ASTElement sourceAst = lastConcreteAst.get(0);
									Error err = new Error("Assembling in this context detected a change in the number of fields.\n" +
											"Check and see if your class has illegal duplicate field definitions.", sourceAst.location());
									processErrors(List.of(err), ProblemPhase.BUILD);
								}
							}

							// Only update if the member name/type was untouched.
							if (newMember != null) {
								lastAssembledClass = assembledClass;
								DirectoryPathNode packagePath = memberPath.getParent().getParent();
								ClassMemberPathNode newPath = packagePath.child(lastAssembledClass).child(newMember);
								onUpdatePath(newPath);
							} else {
								ASTElement sourceAst = lastConcreteAst.get(0);
								Error err = new Error("Changing the " + memberType + " name/type is not allowed in the assembler.\n" +
										"Use Recaf's refactoring capabilities to rename fields & methods.", sourceAst.location());
								processErrors(List.of(err), ProblemPhase.BUILD);
							}
						}
						updateLock.set(false);
					}
					/*
					else if (representation instanceof AndroidClassRepresentation androidClassRep) {
						lastAssembledClass = pipeline.getClassInfo(Unchecked.cast(androidClassRep));
					}
					 */

					eachChild(AssemblerBuildConsumer.class, c -> c.consumeClass(result, lastAssembledClass));
				}).ifErr(errors -> processErrors(errors, ProblemPhase.BUILD))
						.ifWarn(warns -> processErrors(warns, ProblemLevel.WARN, ProblemPhase.BUILD));
			} catch (Throwable ex) {
				logger.error("Uncaught exception when assembling contents of {}", path, ex);
				FxThreadUtil.run(() -> Animations.animateFailure(editor, 1000));
			}
		});
	}
Build the contents of the editor's text and update the workspace when successful.

@return Future of parse completion.
recaf-ui/src/main/java/software/coley/recaf/ui/pane/editing/assembler/AssemblerPane.java