docs: public boolean preValidateInfoTopic(final InfoTopic infoTopic, final ContentSpec contentSpec, final Map<String,
              InfoTopic> infoTopics) {
          // Check if the app should be shutdown
          if (isShuttingDown.get()) {
              shutdown.set(true);
              return false;
          }
  
          boolean valid = true;
  
          // Checks that the id isn't null and is a valid topic ID
          if (infoTopic.getId() == null || !infoTopic.getId().matches(CSConstants.ALL_TOPIC_ID_REGEX)) {
              log.error(String.format(ProcessorConstants.ERROR_INVALID_TOPIC_ID_MSG, infoTopic.getLineNumber(), infoTopic.getText()));
              valid = false;
          }
  
          // Check that we aren't using translations for anything but existing topics
          if (!infoTopic.isTopicAnExistingTopic()) {
              // Check that we aren't processing translations
              if (processingOptions.isTranslation()) {
                  log.error(String.format(ProcessorConstants.ERROR_TOPIC_NO_NEW_TRANSLATION_TOPIC, infoTopic.getLineNumber(),
                          infoTopic.getText()));
                  valid = false;
              }
          }
  
          // Check that we are allowed to create new topics
          if (!infoTopic.isTopicAnExistingTopic() && !processingOptions.isAllowNewTopics()) {
              log.error(String.format(ProcessorConstants.ERROR_TOPIC_NO_NEW_TOPIC_BUILD, infoTopic.getLineNumber(), infoTopic.getText()));
              valid = false;
          }
  
          // Existing Topics
          if (infoTopic.isTopicAnExistingTopic()) {
              // Check that tags aren't trying to be removed
              if (!infoTopic.getRemoveTags(false).isEmpty()) {
                  log.error(String.format(ProcessorConstants.ERROR_TOPIC_EXISTING_TOPIC_CANNOT_REMOVE_TAGS, infoTopic.getLineNumber(),
                          infoTopic.getText()));
                  valid = false;
              }
  
              // Check that tags aren't trying to be added to a revision
              if (processingOptions.isPrintChangeWarnings() && infoTopic.getRevision() != null && !infoTopic.getTags(false).isEmpty()) {
                  log.warn(
                          String.format(ProcessorConstants.WARN_TAGS_IGNORE_MSG, infoTopic.getLineNumber(), "revision", infoTopic.getText()));
              }
  
              // Check that the assigned writer and description haven't been set
              if (infoTopic.getAssignedWriter(false) != null || infoTopic.getDescription(false) != null) {
                  log.error(
                          String.format(ProcessorConstants.ERROR_TOPIC_EXISTING_BAD_OPTIONS, infoTopic.getLineNumber(), infoTopic.getText()));
                  valid = false;
              }
  
              // Check that we aren't processing translations
              if (!infoTopic.getTags(true).isEmpty() && processingOptions.isTranslation()) {
                  log.error(String.format(ProcessorConstants.ERROR_TOPIC_NO_TAGS_TRANSLATION_TOPIC, infoTopic.getLineNumber(),
                          infoTopic.getText()));
                  valid = false;
              }
          }
          // Duplicated Topics
          else if (infoTopic.isTopicADuplicateTopic()) {
              String temp = "N" + infoTopic.getId().substring(1);
  
              // Check that the topic exists in the content specification
              if (!infoTopics.containsKey(temp)) {
                  log.error(String.format(ProcessorConstants.ERROR_TOPIC_NONEXIST_MSG, infoTopic.getLineNumber(), infoTopic.getText()));
                  valid = false;
              }
              // Cloned Topics
          } else if (infoTopic.isTopicAClonedTopic()) {
              // Check if a description or type exists. If one does then generate an error.
              if (infoTopic.getDescription(false) != null && !infoTopic.getDescription(false).equals("")) {
                  log.error(String.format(ProcessorConstants.ERROR_TOPIC_CLONED_BAD_OPTIONS, infoTopic.getLineNumber(), infoTopic.getText()));
                  valid = false;
              }
              // Duplicated Cloned Topics
          } else if (infoTopic.isTopicAClonedDuplicateTopic()) {
              // Find the duplicate topic in the content spec
              final String topicId = infoTopic.getId().substring(1);
              int count = 0;
              for (final Entry<String, InfoTopic> entry : infoTopics.entrySet()) {
                  final String uniqueTopicId = entry.getKey();
  
                  if (uniqueTopicId.endsWith(topicId) && !uniqueTopicId.endsWith(infoTopic.getId())) {
                      count++;
                  }
              }
  
              // Check that the topic exists
              if (count == 0) {
                  log.error(String.format(ProcessorConstants.ERROR_TOPIC_NONEXIST_MSG, infoTopic.getLineNumber(), infoTopic.getText()));
                  valid = false;
              }
              // Check that the referenced topic is unique
              else if (count > 1) {
                  log.error(
                          String.format(ProcessorConstants.ERROR_TOPIC_DUPLICATE_CLONES_MSG, infoTopic.getLineNumber(), infoTopic.getText()));
                  valid = false;
              }
          }
  
          // Check for conflicting conditions
          checkForConflictingCondition(infoTopic, contentSpec);
  
          return valid;
      }