001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.console.views;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.*;
022
023/**
024 * Serving-path allowlist of renderer ids that may be <em>named</em> on a fill sink
025 * (a field-grid catalog {@code render} entry or {@link PopoverField#render}).
026 *
027 * <p>
028 * This does not freeze JavaScript functions; the client {@code resolveSinkRenderer} lookup owns that.  The
029 * table-cell render path does not call this helper (unknown ids still warn-and-fall-back).
030 *
031 * @since 10.0.0
032 */
033public final class SinkRenderAllowlist {
034
035   /**
036    * Built-in ids safe to name on a field-grid fill sink (and the JS frozen-builtin set).
037    *
038    * <p>
039    * {@code pill} is a fill-sink built-in whose sink renderer is a <b>display-only</b> variant of the cell renderer:
040    * the client's {@code resolveSinkRenderer("pill")} never emits {@code role="button"}, and
041    * serving-path validation forbids a {@code meta.action} on a sink pill outright (a fill
042    * sink has no {@code rowActions} in scope to bind one to).
043    *
044    * <p>
045    * {@code code} is a minimal monospace,
046    * whitespace-preserving, HTML-escaped source-text renderer intended for a field-grid catalog entry inside a
047    * row-detail region &mdash; no language hint or syntax highlighting on this first pass.
048    */
049   public static final Set<String> BUILTIN_IDS = Set.of(
050      "date", "datetime", "ts-zulu", "bool", "linked", "truncate", "json", "decimal", "tag", "progress", "pill",
051      "code"
052   );
053
054   /**
055    * Text-shaped built-ins allowed on a {@link PopoverField} (no tags in {@code display()} when popup is forced
056    * off).  A subset of {@link #BUILTIN_IDS}.
057    */
058   public static final Set<String> POPOVER_TEXT_IDS = Set.of(
059      "date", "bool", "decimal", "datetime", "ts-zulu"
060   );
061
062   private SinkRenderAllowlist() {}
063
064   /**
065    * Accepts a frozen built-in id.
066    *
067    * @param renderId The renderer id.  Must not be <jk>null</jk> or blank.
068    * @throws IllegalArgumentException If the id is not a built-in.
069    */
070   public static void assertAllowed(String renderId) {
071      if (ib(renderId))
072         throw iaex("Render id must not be null or blank.");
073      if (BUILTIN_IDS.contains(renderId))
074         return;
075      throw iaex("Render id '%s' is not an allowed fill-sink renderer.", renderId);
076   }
077
078   /**
079    * Accepts only the text-shaped popover built-ins.  Custom ids are never allowed on a popover.
080    *
081    * @param renderId The renderer id.  Must not be <jk>null</jk> or blank.
082    * @throws IllegalArgumentException If the id is not in {@link #POPOVER_TEXT_IDS}.
083    */
084   public static void assertPopoverAllowed(String renderId) {
085      if (ib(renderId))
086         throw iaex("PopoverField render id must not be null or blank.");
087      if (!POPOVER_TEXT_IDS.contains(renderId))
088         throw iaex("PopoverField render id '%s' is not a text-shaped built-in.", renderId);
089   }
090}