|
@@ -75,7 +75,6 @@ import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionT
|
|
|
import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.mapParam;
|
|
|
import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.param;
|
|
|
import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.paramWithoutAnnotation;
|
|
|
-import static org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle.GA;
|
|
|
|
|
|
/**
|
|
|
* This class exists to support the new Docs V3 system.
|
|
@@ -99,12 +98,6 @@ public abstract class DocsV3Support {
|
|
|
|
|
|
protected static final String DOCS_WARNING = "% " + DOCS_WARNING_JSON + "\n\n";
|
|
|
|
|
|
- static final String PREVIEW_CALLOUT = """
|
|
|
- Do not use on production environments. This functionality is in technical preview and
|
|
|
- may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview
|
|
|
- are not subject to the support SLA of official GA features.
|
|
|
- """;
|
|
|
-
|
|
|
static FunctionDocsSupport forFunctions(String name, Class<?> testClass) {
|
|
|
return new FunctionDocsSupport(name, testClass);
|
|
|
}
|
|
@@ -599,73 +592,35 @@ public abstract class DocsV3Support {
|
|
|
writeToTempSnippetsDir("functionNamedParams", rendered.toString());
|
|
|
}
|
|
|
|
|
|
- private String makeCallout(String type, String text) {
|
|
|
- return ":::{" + type + "}\n" + text.trim() + "\n:::\n";
|
|
|
- }
|
|
|
-
|
|
|
- private String makePreviewText(boolean preview, FunctionAppliesTo[] functionAppliesTos) {
|
|
|
- String appliesToTextWithAT = appliesToText(functionAppliesTos);
|
|
|
- String appliesToText = appliesToTextWithoutAppliesTo(functionAppliesTos);
|
|
|
- StringBuilder previewText = new StringBuilder();
|
|
|
- if (preview) {
|
|
|
- // We have a preview flag, use the WARNING callout
|
|
|
- previewText.append(makeCallout("warning", "\n" + PREVIEW_CALLOUT + "\n")).append("\n");
|
|
|
- }
|
|
|
- if (appliesToTextWithAT.isEmpty() == false) {
|
|
|
- // No additional text, just use the plan applies_to syntax
|
|
|
- previewText.append(appliesToTextWithAT);
|
|
|
- } else if (appliesToText.isEmpty() == false) {
|
|
|
- // We have extra descriptive text, nest inside a NOTE for emphasis
|
|
|
- previewText.append(makeCallout("note", appliesToText));
|
|
|
- }
|
|
|
- return previewText.toString();
|
|
|
- }
|
|
|
-
|
|
|
- private String appliesToText(FunctionAppliesTo[] functionAppliesTos) {
|
|
|
+ private String makeAppliesToText(FunctionAppliesTo[] functionAppliesTos, boolean preview) {
|
|
|
StringBuilder appliesToText = new StringBuilder();
|
|
|
if (functionAppliesTos.length > 0) {
|
|
|
appliesToText.append("```{applies_to}\n");
|
|
|
+ StringBuilder stackEntries = new StringBuilder();
|
|
|
+
|
|
|
for (FunctionAppliesTo appliesTo : functionAppliesTos) {
|
|
|
- if (appliesTo.description().isEmpty() == false) {
|
|
|
- // If any of the appliesTo has descriptive text, we need to format things differently
|
|
|
- return "";
|
|
|
+ if (stackEntries.isEmpty() == false) {
|
|
|
+ stackEntries.append(", ");
|
|
|
}
|
|
|
- appliesToText.append("product: ");
|
|
|
- appendLifeCycleAndVersion(appliesToText, appliesTo);
|
|
|
- appliesToText.append("\n");
|
|
|
- if (appliesTo.serverless() && appliesTo.lifeCycle().serverlessLifecycle() == GA) {
|
|
|
- appliesToText.append("serverless: ").append(GA).append("\n");
|
|
|
+ stackEntries.append(appliesTo.lifeCycle().name().toLowerCase(Locale.ROOT));
|
|
|
+ if (appliesTo.version().isEmpty() == false) {
|
|
|
+ stackEntries.append(" ").append(appliesTo.version());
|
|
|
}
|
|
|
}
|
|
|
- appliesToText.append("```\n");
|
|
|
- }
|
|
|
- return appliesToText.toString();
|
|
|
- }
|
|
|
|
|
|
- private String appliesToTextWithoutAppliesTo(FunctionAppliesTo[] functionAppliesTos) {
|
|
|
- StringBuilder appliesToText = new StringBuilder();
|
|
|
- if (functionAppliesTos.length > 0) {
|
|
|
- appliesToText.append("\n");
|
|
|
- for (FunctionAppliesTo appliesTo : functionAppliesTos) {
|
|
|
- appliesToText.append("###### ");
|
|
|
- if (appliesTo.serverless() && appliesTo.lifeCycle().serverlessLifecycle() == GA) {
|
|
|
- appliesToText.append("Serverless: ").append(GA).append(", Elastic Stack: ");
|
|
|
- }
|
|
|
- appendLifeCycleAndVersion(appliesToText, appliesTo);
|
|
|
- appliesToText.append("\n");
|
|
|
- if (appliesTo.description().isEmpty() == false) {
|
|
|
- appliesToText.append(appliesTo.description()).append("\n\n");
|
|
|
- }
|
|
|
+ // Add the stack entries
|
|
|
+ if (stackEntries.isEmpty() == false) {
|
|
|
+ appliesToText.append("stack: ").append(stackEntries).append("\n");
|
|
|
}
|
|
|
- }
|
|
|
- return appliesToText.toString();
|
|
|
- }
|
|
|
|
|
|
- private void appendLifeCycleAndVersion(StringBuilder appliesToText, FunctionAppliesTo appliesTo) {
|
|
|
- appliesToText.append(appliesTo.lifeCycle().name());
|
|
|
- if (appliesTo.version().isEmpty() == false) {
|
|
|
- appliesToText.append(" ").append(appliesTo.version());
|
|
|
+ // Only specify serverless if it's preview, using the preview boolean (GA is the default)
|
|
|
+ if (preview) {
|
|
|
+ appliesToText.append("serverless: preview\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ appliesToText.append("```\n");
|
|
|
}
|
|
|
+ return appliesToText.toString();
|
|
|
}
|
|
|
|
|
|
private void renderFullLayout(FunctionInfo info, boolean hasExamples, boolean hasAppendix, boolean hasFunctionOptions)
|
|
@@ -674,7 +629,7 @@ public abstract class DocsV3Support {
|
|
|
StringBuilder rendered = new StringBuilder(
|
|
|
DOCS_WARNING + """
|
|
|
$HEAD$ `$UPPER_NAME$` [esql-$NAME$]
|
|
|
- $PREVIEW_CALLOUT$
|
|
|
+ $APPLIES_TO$
|
|
|
**Syntax**
|
|
|
|
|
|
:::{image} ../../../images/$CATEGORY$/$NAME$.svg
|
|
@@ -686,7 +641,7 @@ public abstract class DocsV3Support {
|
|
|
.replace("$NAME$", name)
|
|
|
.replace("$CATEGORY$", category)
|
|
|
.replace("$UPPER_NAME$", name.toUpperCase(Locale.ROOT))
|
|
|
- .replace("$PREVIEW_CALLOUT$", makePreviewText(info.preview(), info.appliesTo()))
|
|
|
+ .replace("$APPLIES_TO$", makeAppliesToText(info.appliesTo(), info.preview()))
|
|
|
);
|
|
|
for (String section : new String[] { "parameters", "description", "types" }) {
|
|
|
rendered.append(addInclude(section));
|
|
@@ -1027,6 +982,11 @@ public abstract class DocsV3Support {
|
|
|
builder.append("**Examples**\n\n");
|
|
|
}
|
|
|
for (Example example : info.examples()) {
|
|
|
+ if (example.applies_to().isEmpty() == false) {
|
|
|
+ builder.append("```{applies_to}\n");
|
|
|
+ builder.append(example.applies_to()).append("\n");
|
|
|
+ builder.append("```\n\n");
|
|
|
+ }
|
|
|
if (example.description().isEmpty() == false) {
|
|
|
builder.append(replaceLinks(example.description().trim()));
|
|
|
builder.append("\n\n");
|
|
@@ -1059,7 +1019,9 @@ public abstract class DocsV3Support {
|
|
|
StringBuilder builder = new StringBuilder();
|
|
|
builder.append(DOCS_WARNING);
|
|
|
builder.append("### ").append(titleName.toUpperCase(Locale.ROOT)).append("\n");
|
|
|
- builder.append(replaceLinks(info.description())).append("\n\n");
|
|
|
+ String cleanedDesc = replaceLinks(info.description());
|
|
|
+ cleanedDesc = removeAppliesToBlocks(cleanedDesc);
|
|
|
+ builder.append(cleanedDesc).append("\n\n");
|
|
|
|
|
|
if (info.examples().length > 0) {
|
|
|
Example example = info.examples()[0];
|
|
@@ -1068,7 +1030,9 @@ public abstract class DocsV3Support {
|
|
|
builder.append("\n```\n");
|
|
|
}
|
|
|
if (Strings.isNullOrEmpty(info.note()) == false) {
|
|
|
- builder.append("Note: ").append(replaceLinks(info.note())).append("\n");
|
|
|
+ String cleanedNote = replaceLinks(info.note());
|
|
|
+ cleanedNote = removeAppliesToBlocks(cleanedNote);
|
|
|
+ builder.append("Note: ").append(cleanedNote).append("\n");
|
|
|
}
|
|
|
String rendered = builder.toString();
|
|
|
logger.info("Writing kibana inline docs for [{}]:\n{}", name, rendered);
|
|
@@ -1105,9 +1069,13 @@ public abstract class DocsV3Support {
|
|
|
if (titleName != null && titleName.equals(name) == false) {
|
|
|
builder.field("titleName", titleName);
|
|
|
}
|
|
|
- builder.field("description", removeAsciidocLinks(info.description()));
|
|
|
+ String cleanedDescription = removeAsciidocLinks(info.description());
|
|
|
+ cleanedDescription = removeAppliesToBlocks(cleanedDescription);
|
|
|
+ builder.field("description", cleanedDescription);
|
|
|
if (Strings.isNullOrEmpty(info.note()) == false) {
|
|
|
- builder.field("note", removeAsciidocLinks(info.note()));
|
|
|
+ String cleanedNote = removeAsciidocLinks(info.note());
|
|
|
+ cleanedNote = removeAppliesToBlocks(cleanedNote);
|
|
|
+ builder.field("note", cleanedNote);
|
|
|
}
|
|
|
// TODO aliases
|
|
|
|
|
@@ -1152,7 +1120,8 @@ public abstract class DocsV3Support {
|
|
|
builder.field("type", sig.getKey().get(i).esNameIfPossible());
|
|
|
}
|
|
|
builder.field("optional", arg.optional());
|
|
|
- builder.field("description", arg.description());
|
|
|
+ String cleanedParamDesc = removeAppliesToBlocks(arg.description());
|
|
|
+ builder.field("description", cleanedParamDesc);
|
|
|
builder.endObject();
|
|
|
}
|
|
|
builder.endArray();
|
|
@@ -1190,6 +1159,20 @@ public abstract class DocsV3Support {
|
|
|
return md.replaceAll("\\[(\\s*`?[^]]+?`?\\s*)]\\(([^()\\s]+(?:\\([^()]*\\)[^()]*)*)\\)", "$1");
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Removes applies_to blocks from content intended for Kibana consumption.
|
|
|
+ * Applies_to syntax like {applies_to}`stack: ga 9.1.0` should not appear in Kibana JSON files.
|
|
|
+ */
|
|
|
+ private static String removeAppliesToBlocks(String content) {
|
|
|
+ if (content == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Remove {applies_to}`...` blocks using regex
|
|
|
+ // Matches: {applies_to}`anything` including backticks and content inside
|
|
|
+ return content.replaceAll("\\s*\\{applies_to\\}`[^`]*`\\s*", "");
|
|
|
+ }
|
|
|
+
|
|
|
private List<Map.Entry<List<DataType>, DataType>> sortedSignatures() {
|
|
|
List<Map.Entry<List<DataType>, DataType>> sortedSignatures = new ArrayList<>(signatures.get().entrySet());
|
|
|
sortedSignatures.sort((lhs, rhs) -> {
|