public ValidatedResult<Model> assemble() {
        if (traitFactory == null) {
            traitFactory = LazyTraitFactoryHolder.INSTANCE;
        }

        if (validatorFactory == null) {
            validatorFactory = ModelValidator.defaultValidationFactory();
        }

        // Create a singular, composed event decorator used to modify events.
        ValidationEventDecorator decorator = ValidationEventDecorator.compose(validatorFactory.loadDecorators());

        Model prelude = disablePrelude ? null : Prelude.getPreludeModel();

        // As issues are encountered, they are decorated and then emitted.
        LoadOperationProcessor processor = new LoadOperationProcessor(
                traitFactory,
                prelude,
                areUnknownTraitsAllowed(),
                validationEventListener,
                decorator);
        List<ValidationEvent> events = processor.events();

        // Register manually added metadata.
        addMetadataToProcessor(metadata, processor);

        // Register manually added shapes. Skip members because they are part of aggregate shapes.
        shapes.forEach(processor::putCreatedShape);

        // Register manually added Models.
        for (Model model : mergeModels) {
            // Add manually added metadata from the Model.
            addMetadataToProcessor(model.getMetadata(), processor);
            model.shapes().forEach(processor::putCreatedShape);
        }

        // Load parsed AST nodes and merge them into the processor.
        for (Node node : documentNodes) {
            try {
                ModelLoader.loadParsedNode(node, processor);
            } catch (SourceException e) {
                processor.accept(new LoadOperation.Event(ValidationEvent.fromSourceException(e)));
            }
        }

        if (stringTable == null) {
            stringTable = new StringTable();
        }

        // Load model files into the processor.
        for (Map.Entry<String, Supplier<InputStream>> entry : inputStreamModels.entrySet()) {
            try {
                ModelLoader.load(traitFactory, properties, entry.getKey(), processor, entry.getValue(), stringTable);
            } catch (SourceException e) {
                processor.accept(new LoadOperation.Event(ValidationEvent.fromSourceException(e)));
            }
        }

        // Register manually added traits. Do this after loading any other sources of shapes
        // so that traits can be applied to them.
        for (Pair<ShapeId, Trait> entry : pendingTraits) {
            processor.accept(LoadOperation.ApplyTrait.from(entry.getKey(), entry.getValue()));
        }

        Model processedModel = processor.buildModel();

        // Do the 1.0 -> 2.0 transform before full-model validation.
        Model transformed = new ModelInteropTransformer(processedModel, events, processor::getShapeVersion).transform();

        if (disableValidation || LoaderUtils.containsErrorEvents(events)) {
            // All events have been emitted and decorated at this point.
            return new ValidatedResult<>(transformed, events);
        }

        try {
            List<ValidationEvent> mergedEvents = ModelValidator.builder()
                    .addValidators(validators)
                    .validatorFactory(validatorFactory, decorator)
                    .eventListener(validationEventListener)
                    .includeEvents(events)
                    .legacyValidationMode((boolean) properties.getOrDefault("LEGACY_VALIDATION_MODE", false))
                    .build()
                    .validate(transformed);
            return new ValidatedResult<>(transformed, mergedEvents);
        } catch (SourceException e) {
            events.add(ValidationEvent.fromSourceException(e));
            return new ValidatedResult<>(transformed, events);
        }
    }
Assembles the model and returns the validated result.

@return Returns the validated result that optionally contains a Model
 and validation events.
smithy-model/src/main/java/software/amazon/smithy/model/loader/ModelAssembler.java