public Model getModelWithoutTraitShapes(Model model, Predicate<Shape> keepFilter) {
        Model.Builder builder = Model.builder();

        // ScrubTraitDefinitions is used to removed traits and trait shapes.
        // However, the returned model can't be returned directly because
        // as traits are removed, uses of that trait are removed. Instead,
        // a model is created by getting all shape IDs from the modified
        // model, grabbing shapes from the original model, and building a new
        // Model.
        scrubTraitDefinitions(model, keepFilter).shapes()
                .map(Shape::getId)
                .map(model::getShape)
                .map(Optional::get)
                .forEach(builder::addShape);

        return builder.build();
    }
Gets all shapes from a model where shapes that define traits or shapes
that are only used as part of a trait definition have been removed.

@param model Model that contains shapes.
@param keepFilter Predicate function that accepts a trait shape (that
 has the {@link TraitDefinition} trait) and returns true to remove the
 definition or false to keep the definition in the model.
@return Returns a model that contains matching shapes.
smithy-model/src/main/java/software/amazon/smithy/model/transform/ModelTransformer.java