2020import static org .spongepowered .configurate .loader .ParsingException .UNKNOWN_POS ;
2121
2222import com .google .errorprone .annotations .ForOverride ;
23+ import net .kyori .option .Option ;
24+ import net .kyori .option .OptionSchema ;
25+ import net .kyori .option .OptionState ;
26+ import net .kyori .option .value .ValueSource ;
27+ import org .checkerframework .checker .nullness .qual .MonotonicNonNull ;
2328import org .checkerframework .checker .nullness .qual .Nullable ;
2429import org .spongepowered .configurate .ConfigurateException ;
2530import org .spongepowered .configurate .ConfigurationNode ;
4550import java .util .Iterator ;
4651import java .util .List ;
4752import java .util .concurrent .Callable ;
53+ import java .util .function .Consumer ;
4854import java .util .function .UnaryOperator ;
4955import java .util .regex .Pattern ;
5056
@@ -119,7 +125,7 @@ public abstract class AbstractConfigurationLoader<N extends ScopedConfigurationN
119125 protected AbstractConfigurationLoader (final Builder <?, ?> builder , final CommentHandler [] commentHandlers ) {
120126 this .source = builder .source ();
121127 this .sink = builder .sink ();
122- this .headerMode = builder .headerMode ( );
128+ this .headerMode = builder .optionState (). value ( Builder . HEADER_MODE );
123129 this .commentHandlers = UnmodifiableCollections .toList (commentHandlers );
124130 this .defaultOptions = builder .defaultOptions ();
125131 }
@@ -264,63 +270,107 @@ public final boolean canSave() {
264270 */
265271 public abstract static class Builder <T extends Builder <T , L >, L extends AbstractConfigurationLoader <?>> {
266272
267- protected static final LoaderOptionSource DEFAULT_OPTIONS_SOURCE = LoaderOptionSource .composite (
268- LoaderOptionSource .systemProperties (),
269- LoaderOptionSource .environmentVariables ()
270- );
273+ private static final String CONFIGURATE_PREFIX = "configurate" ;
271274
272- protected HeaderMode headerMode = HeaderMode .PRESERVE ;
275+ private static final OptionSchema .Mutable UNSAFE_SCHEMA = OptionSchema .emptySchema ();
276+ protected static final OptionSchema SCHEMA = UNSAFE_SCHEMA .frozenView ();
277+
278+ /**
279+ * How to read and emit headers discovered on documents processed by
280+ * the created loader.
281+ *
282+ * @since 4.2.0
283+ */
284+ public static final Option <HeaderMode > HEADER_MODE = UNSAFE_SCHEMA .enumOption ("header" , HeaderMode .class , HeaderMode .PRESERVE );
285+
286+ @ Deprecated
287+ protected HeaderMode headerMode ;
288+ private OptionState .@ MonotonicNonNull Builder optionBuilder ;
289+ private @ Nullable OptionState optionState ;
273290 protected @ Nullable Callable <BufferedReader > source ;
274291 protected @ Nullable Callable <BufferedWriter > sink ;
275292 protected ConfigurationOptions defaultOptions = ConfigurationOptions .defaults ();
276293
277294 /**
278295 * Create a new builder.
279296 *
280- * <p>This is where any custom default options can be applied.</p>
281- *
282- * <p>At the end of this constructor, {@link #from(LoaderOptionSource)}
283- * should be called with {@link #DEFAULT_OPTIONS_SOURCE} to read any supported
284- * options from environment variables and system properties.</p>
285- *
286297 * @since 4.0.0
287298 */
288299 protected Builder () {}
289300
290301 /**
291- * Populate this builder by reading options from the provided source.
302+ * Begin building an option state, initialized from the current
303+ * environment.
292304 *
293- * <p>These options should control all options for the reading and
294- * representation of nodes produced by this loader, specifically
295- * excluding the {@link #source()} and {@link #sink()} of the loader,
296- * and the {@link #defaultOptions()}.</p>
297- *
298- * <p>The options read from the provided source are format-defined.</p>
305+ * @return the pre-initialized option state builder
306+ * @since 4.2.0
307+ */
308+ protected OptionState .Builder optionStateBuilder () {
309+ if (this .optionBuilder == null ) {
310+ this .optionState = null ;
311+ this .optionBuilder = this .optionSchema ().stateBuilder ()
312+ .values (ValueSource .systemProperty (CONFIGURATE_PREFIX ))
313+ .values (ValueSource .environmentVariable (CONFIGURATE_PREFIX ));
314+ }
315+ return this .optionBuilder ;
316+ }
317+
318+ /**
319+ * Compute a snapshot of the currently set options for created loaders.
299320 *
300- * @param source the source to read
301- * @return this builder (for chaining)
321+ * @return the option state
302322 * @since 4.2.0
303323 */
304- public final T from (final LoaderOptionSource source ) {
305- requireNonNull (source , "source" );
306- final @ Nullable HeaderMode headerMode = source .getEnum (HeaderMode .class , "header" );
307- if (headerMode != null ) {
308- this .headerMode = headerMode ;
324+ public OptionState optionState () {
325+ if (this .optionState == null ) {
326+ this .optionState = this .optionStateBuilder ().build ();
309327 }
310- this .populate (source );
328+ return this .optionState ;
329+ }
330+
331+ /**
332+ * Set the option state for this loader to the provided state.
333+ *
334+ * <p>The provided state must be within the
335+ * {@link #optionSchema() loader's schema}.</p>
336+ *
337+ * @param state the state
338+ * @return this builder
339+ * @since 4.2.0
340+ */
341+ public T optionState (final OptionState state ) {
342+ this .optionBuilder = this .optionSchema ().stateBuilder ()
343+ .values (state );
344+ this .optionState = null ;
345+
311346 return this .self ();
312347 }
313348
314349 /**
315- * Populate options from the provided source .
350+ * Modify the state of loader options set on this loader .
316351 *
317- * <p>The source will have already been validated for nullness.</p>
352+ * @param builderConsumer a consumer that receives the modifier to
353+ * perform changes
354+ * @return this builder
355+ * @since 4.2.0
356+ */
357+ public T editOptions (final Consumer <OptionState .Builder > builderConsumer ) {
358+ this .optionState = null ;
359+ builderConsumer .accept (this .optionStateBuilder ());
360+ return this .self ();
361+ }
362+
363+ /**
364+ * Get the schema of available options that can be set on this loader.
318365 *
319- * @param options the options to read
366+ * <p>This schema should inherit from {@link #UNSAFE_SCHEMA}.</p>
367+ *
368+ * @return the option schema
320369 * @since 4.2.0
321370 */
322371 @ ForOverride
323- protected void populate (final LoaderOptionSource options ) {
372+ protected OptionSchema optionSchema () {
373+ return SCHEMA ; // fallback
324374 }
325375
326376 @ SuppressWarnings ("unchecked" )
@@ -434,7 +484,7 @@ public T sink(final @Nullable Callable<BufferedWriter> sink) {
434484 * @since 4.0.0
435485 */
436486 public T headerMode (final HeaderMode mode ) {
437- this .headerMode = requireNonNull ( mode , " mode" );
487+ this .optionStateBuilder (). value ( Builder . HEADER_MODE , mode );
438488 return self ();
439489 }
440490
@@ -444,8 +494,14 @@ public T headerMode(final HeaderMode mode) {
444494 * @return the header mode
445495 * @since 4.0.0
446496 */
497+ @ SuppressWarnings ("deprecation" )
447498 public HeaderMode headerMode () {
448- return this .headerMode ;
499+ // manually overridden for some reason?
500+ if (this .headerMode != null ) {
501+ this .optionStateBuilder ().value (HEADER_MODE , this .headerMode );
502+ this .headerMode = null ;
503+ }
504+ return this .optionState ().value (HEADER_MODE );
449505 }
450506
451507 /**
0 commit comments