Wrap rison-node to improve types (#146649)

@maximpn brought up the issues caused by the types required by the
rison-node package, which attempted to communicate that "encoded values
must be primitive values, or recursive arrays/object of primitive
values". This isn't actually expressible in TypeScript, which lead to
many instances of `rison.encode(value as unknown as RisonValue)` which
is useless. Additionally, the rison-node library actually supports any
value and will either produce valid rison or `undefined` for that value.

To address this I'm adding a wrapper function which accepts `any` and
returns a `string`. If rison-node is totally unable to produce any rison
for the value (because the value is `undefined` or some other type like
Symbol or BigInt) the `encode()` function will throw. If you're
accepting arbitrary input you can use the `encodeUnknown()` function,
which will return a string or undefined, if the value you provided has
zero rison representation.

Like JSON.stringify() any non-circular primitive, object, or array can
be encoded with either function. If the values within those objects are
not encodable (functions, RegExps, etc) then they will be skipped. Any
object/array with the `toJSON()` method will be converted to JSON first,
and if the prototype of the object has the `encode_rison()` method it
will be used to convert he value into rison.

The changes in this PR are mostly updating usage of rison-node to use
`@kbn/rison` (which is also enforced by eslint). There are also several
changes which remove unnecessary casting.
This commit is contained in:
Spencer 2022-12-01 08:33:56 -07:00 committed by GitHub
parent 6f7c6ad947
commit 2e314db2ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
82 changed files with 491 additions and 144 deletions

1
.github/CODEOWNERS vendored
View file

@ -966,6 +966,7 @@ packages/kbn-plugin-helpers @elastic/kibana-operations
packages/kbn-react-field @elastic/kibana-app-services
packages/kbn-repo-source-classifier @elastic/kibana-operations
packages/kbn-repo-source-classifier-cli @elastic/kibana-operations
packages/kbn-rison @elastic/kibana-operations
packages/kbn-rule-data-utils @elastic/security-detections-response @elastic/actionable-observability @elastic/response-ops
packages/kbn-safer-lodash-set @elastic/kibana-security
packages/kbn-securitysolution-autocomplete @elastic/security-solution-platform

View file

@ -356,6 +356,7 @@
"@kbn/osquery-io-ts-types": "link:bazel-bin/packages/kbn-osquery-io-ts-types",
"@kbn/plugin-discovery": "link:bazel-bin/packages/kbn-plugin-discovery",
"@kbn/react-field": "link:bazel-bin/packages/kbn-react-field",
"@kbn/rison": "link:bazel-bin/packages/kbn-rison",
"@kbn/rule-data-utils": "link:bazel-bin/packages/kbn-rule-data-utils",
"@kbn/safer-lodash-set": "link:bazel-bin/packages/kbn-safer-lodash-set",
"@kbn/securitysolution-autocomplete": "link:bazel-bin/packages/kbn-securitysolution-autocomplete",

View file

@ -276,6 +276,7 @@ filegroup(
"//packages/kbn-react-field:build",
"//packages/kbn-repo-source-classifier:build",
"//packages/kbn-repo-source-classifier-cli:build",
"//packages/kbn-rison:build",
"//packages/kbn-rule-data-utils:build",
"//packages/kbn-safer-lodash-set:build",
"//packages/kbn-securitysolution-autocomplete:build",
@ -640,6 +641,7 @@ filegroup(
"//packages/kbn-react-field:build_types",
"//packages/kbn-repo-source-classifier:build_types",
"//packages/kbn-repo-source-classifier-cli:build_types",
"//packages/kbn-rison:build_types",
"//packages/kbn-rule-data-utils:build_types",
"//packages/kbn-safer-lodash-set:build_types",
"//packages/kbn-securitysolution-autocomplete:build_types",

View file

@ -131,6 +131,10 @@ module.exports = {
from: '@elastic/apm-synthtrace',
to: '@kbn/apm-synthtrace',
},
{
from: 'rison-node',
to: '@kbn/rison',
},
],
],

View file

@ -0,0 +1,123 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
PKG_DIRNAME = "kbn-rison"
PKG_REQUIRE_NAME = "@kbn/rison"
SOURCE_FILES = glob(
[
"**/*.ts",
],
exclude = [
"**/*.config.js",
"**/*.mock.*",
"**/*.test.*",
"**/*.stories.*",
"**/__snapshots__/**",
"**/integration_tests/**",
"**/mocks/**",
"**/scripts/**",
"**/storybook/**",
"**/test_fixtures/**",
"**/test_helpers/**",
],
)
SRCS = SOURCE_FILES
filegroup(
name = "srcs",
srcs = SRCS,
)
NPM_MODULE_EXTRA_FILES = [
"package.json",
]
# In this array place runtime dependencies, including other packages and NPM packages
# which must be available for this code to run.
#
# To reference other packages use:
# "//repo/relative/path/to/package"
# eg. "//packages/kbn-utils"
#
# To reference a NPM package use:
# "@npm//name-of-package"
# eg. "@npm//lodash"
RUNTIME_DEPS = [
"@npm//rison-node",
]
# In this array place dependencies necessary to build the types, which will include the
# :npm_module_types target of other packages and packages from NPM, including @types/*
# packages.
#
# To reference the types for another package use:
# "//repo/relative/path/to/package:npm_module_types"
# eg. "//packages/kbn-utils:npm_module_types"
#
# References to NPM packages work the same as RUNTIME_DEPS
TYPES_DEPS = [
"@npm//@types/node",
"@npm//@types/jest",
]
jsts_transpiler(
name = "target_node",
srcs = SRCS,
build_pkg_name = package_name(),
)
ts_config(
name = "tsconfig",
src = "tsconfig.json",
deps = [
"//:tsconfig.base.json",
"//:tsconfig.bazel.json",
],
)
ts_project(
name = "tsc_types",
args = ['--pretty'],
srcs = SRCS,
deps = TYPES_DEPS,
declaration = True,
emit_declaration_only = True,
out_dir = "target_types",
tsconfig = ":tsconfig",
)
js_library(
name = PKG_DIRNAME,
srcs = NPM_MODULE_EXTRA_FILES,
deps = RUNTIME_DEPS + [":target_node"],
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)
js_library(
name = "npm_module_types",
srcs = NPM_MODULE_EXTRA_FILES,
deps = RUNTIME_DEPS + [":target_node", ":tsc_types"],
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)
pkg_npm(
name = "npm_module",
deps = [":" + PKG_DIRNAME],
)
filegroup(
name = "build",
srcs = [":npm_module"],
visibility = ["//visibility:public"],
)
filegroup(
name = "build_types",
srcs = [":npm_module_types"],
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,3 @@
# @kbn/rison
A simple wrapper around [rison-node](https://github.com/w33ble/rison-node) which gives us types and ensures that values are always encoded to a string.

View file

@ -0,0 +1,20 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export * from './kbn_rison';
import { encode, encodeUnknown, decode, encodeArray, decodeArray } from './kbn_rison';
// maintain compatibility with 'rison-node' and include a default export
// eslint-disable-next-line import/no-default-export
export default {
encode,
encodeUnknown,
decode,
encodeArray,
decodeArray,
};

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-rison'],
};

View file

@ -0,0 +1,99 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import * as Rison from './kbn_rison';
describe('encoding', () => {
it('encodes basic values', () => {
expect(Rison.encode(false)).toMatchInlineSnapshot(`"!f"`);
expect(Rison.encode(true)).toMatchInlineSnapshot(`"!t"`);
expect(Rison.encode(1)).toMatchInlineSnapshot(`"1"`);
expect(Rison.encode([1])).toMatchInlineSnapshot(`"!(1)"`);
expect(Rison.encode(['1'])).toMatchInlineSnapshot(`"!('1')"`);
expect(Rison.encode([null])).toMatchInlineSnapshot(`"!(!n)"`);
expect(Rison.encode([undefined])).toMatchInlineSnapshot(`"!()"`);
expect(Rison.encode(null)).toMatchInlineSnapshot(`"!n"`);
});
it('throws if it received undefined', () => {
expect(() => Rison.encode(undefined)).toThrowErrorMatchingInlineSnapshot(
`"unable to encode value into rison, expected a primative value array or object"`
);
});
it('encodes a complex object', () => {
expect(
Rison.encode({
foo: 1,
bar: {
bax: 1,
bar: [
'x',
{
a: /foo/,
b: new Date(0),
},
],
},
})
).toMatchInlineSnapshot(`"(bar:(bar:!(x,(a:(),b:'1970-01-01T00:00:00.000Z')),bax:1),foo:1)"`);
});
it('encodes arrays directly as well', () => {
expect(Rison.encodeArray([1, 2, 3])).toMatchInlineSnapshot(`"1,2,3"`);
});
});
describe('decoding', () => {
it('decodes a simple rison string', () => {
expect(Rison.decode('!f')).toMatchInlineSnapshot(`false`);
expect(Rison.decode('!t')).toMatchInlineSnapshot(`true`);
expect(Rison.decode('1')).toMatchInlineSnapshot(`1`);
expect(Rison.decode('!(1)')).toMatchInlineSnapshot(`
Array [
1,
]
`);
expect(Rison.decode("!('1')")).toMatchInlineSnapshot(`
Array [
"1",
]
`);
expect(Rison.decode('!(!n)')).toMatchInlineSnapshot(`
Array [
null,
]
`);
expect(Rison.decode('!()')).toMatchInlineSnapshot(`Array []`);
expect(Rison.decode('!n')).toMatchInlineSnapshot(`null`);
});
it('decodes a complex rison string', () => {
expect(Rison.decode(`(bar:(bar:!(x,(a:(),b:'1970-01-01T00:00:00.000Z')),bax:1),foo:1)`))
.toMatchInlineSnapshot(`
Object {
"bar": Object {
"bar": Array [
"x",
Object {
"a": Object {},
"b": "1970-01-01T00:00:00.000Z",
},
],
"bax": 1,
},
"foo": 1,
}
`);
});
it('decodes an encoded array', () => {
expect(Rison.decodeArray('1,2,3')).toMatchInlineSnapshot(`
Array [
1,
2,
3,
]
`);
});
});

View file

@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
// @ts-expect-error untyped module from npm
// eslint-disable-next-line @kbn/eslint/module_migration
import Rison from 'rison-node';
export type RisonValue =
| boolean
| string
| number
| RisonValue[]
| { [key: string]: RisonValue }
| null;
export function encodeUnknown(obj: any): string | undefined {
return Rison.encode(obj);
}
/**
* rison-encode a javascript structure
*/
export function encode(obj: any) {
const rison = encodeUnknown(obj);
if (rison === undefined) {
throw new Error(
'unable to encode value into rison, expected a primative value array or object'
);
}
return rison;
}
/**
* parse a rison string into a javascript structure.
*/
export function decode(rison: string): RisonValue {
return Rison.decode(rison);
}
/**
* rison-encode a javascript array without surrounding parens
*/
export function encodeArray(array: any[]) {
return Rison.encode_array(array);
}
/**
* parse an a-rison string into a javascript structure.
*
* this simply adds array markup around the string before parsing.
*/
export function decodeArray(rison: string): RisonValue[] {
return Rison.decode_array(rison);
}

View file

@ -0,0 +1,7 @@
{
"type": "shared-common",
"id": "@kbn/rison",
"owner": "@elastic/kibana-operations",
"runtimeDeps": [],
"typeDeps": [],
}

View file

@ -0,0 +1,8 @@
{
"name": "@kbn/rison",
"private": true,
"version": "1.0.0",
"main": "./target_node/index.js",
"types": "./target_types/index.d.ts",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.bazel.json",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "target_types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
]
}

View file

@ -62,7 +62,6 @@ RUNTIME_DEPS = [
"@npm//react-router-dom",
"@npm//react-router",
"@npm//react",
"@npm//rison-node",
"@npm//rxjs",
"@npm//styled-components",
"@npm//symbol-observable",
@ -98,7 +97,6 @@ TYPES_DEPS = [
"@npm//react-is",
"@npm//react-router",
"@npm//react-router-dom",
"@npm//rison-node",
"@npm//rxjs",
"@npm//styled-components",
"@npm//symbol-observable",

View file

@ -100,7 +100,6 @@ module.exports = (_, argv) => {
'react-router-dom',
'react-router',
'react',
'rison-node',
'rxjs',
'rxjs/operators',
'styled-components',

View file

@ -51,6 +51,7 @@ RUNTIME_DEPS = [
"//packages/kbn-ui-shared-deps-npm",
"//packages/kbn-ui-theme",
"//packages/kbn-peggy-loader",
"//packages/kbn-rison",
]
TYPES_DEPS = [
@ -107,7 +108,7 @@ webpack(
"$(location webpack.config.js)",
"--output-path",
"$(@D)",
"--no-stats"
"--stats=errors-only"
],
)

View file

@ -77,7 +77,7 @@ const externals = {
'@kbn/es-query': '__kbnSharedDeps__.KbnEsQuery',
'@kbn/std': '__kbnSharedDeps__.KbnStd',
'@kbn/safer-lodash-set': '__kbnSharedDeps__.SaferLodashSet',
'rison-node': '__kbnSharedDeps__.RisonNode',
'@kbn/rison': '__kbnSharedDeps__.KbnRison',
history: '__kbnSharedDeps__.History',
classnames: '__kbnSharedDeps__.Classnames',
'@tanstack/react-query': '__kbnSharedDeps__.ReactQuery',

View file

@ -57,7 +57,7 @@ export const KbnAnalytics = require('@kbn/analytics');
export const KbnEsQuery = require('@kbn/es-query');
export const KbnStd = require('@kbn/std');
export const SaferLodashSet = require('@kbn/safer-lodash-set');
export const RisonNode = require('rison-node');
export const KbnRison = require('@kbn/rison');
export const History = require('history');
export const Classnames = require('classnames');
export const ReactQuery = require('@tanstack/react-query');

View file

@ -2,7 +2,13 @@
load("@npm//@bazel/typescript:index.bzl", _ts_project = "ts_project")
def ts_project(validate = False, **kwargs):
def contains(list, item):
for i in list:
if i == item:
return True
return False
def ts_project(validate = False, deps = [], **kwargs):
"""A macro around the upstream ts_project rule.
Args:
@ -10,7 +16,11 @@ def ts_project(validate = False, **kwargs):
**kwargs: the rest
"""
if contains(deps, "@npm//tslib") == False:
deps = deps + ["@npm//tslib"]
_ts_project(
validate = validate,
deps = deps,
**kwargs
)

View file

@ -7,7 +7,7 @@
*/
import React from 'react';
import rison from 'rison-node';
import rison from '@kbn/rison';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import rison, { RisonValue } from 'rison-node';
import rison from '@kbn/rison';
import { isStateHash, retrieveState, persistState } from '../state_hash';
// should be:
@ -22,14 +22,14 @@ export function decodeState<State>(expandedOrHashedState: string): State {
}
// should be:
// export function encodeState<State extends RisonValue>(expandedOrHashedState: string)
// but this leads to the chain of types mismatches up to BaseStateContainer interfaces,
// as in state containers we don't have any restrictions on state shape
// export function encodeState<State extends RisonValue> but this leads to the chain of
// types mismatches up to BaseStateContainer interfaces, as in state containers we don't
// have any restrictions on state shape
export function encodeState<State>(state: State, useHash: boolean): string {
if (useHash) {
return persistState(state);
} else {
return rison.encode(state as unknown as RisonValue);
return rison.encodeUnknown(state) ?? '';
}
}

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { encode as encodeRison } from 'rison-node';
import { encode as encodeRison } from '@kbn/rison';
import { mockStorage } from '../../storage/hashed_item_store/mock';
import { createStateHash, isStateHash } from './state_hash';

View file

@ -7,7 +7,7 @@
*/
import Handlebars from '@kbn/handlebars';
import { encode, RisonValue } from 'rison-node';
import { encode } from '@kbn/rison';
import dateMath from '@kbn/datemath';
import moment, { Moment } from 'moment';
import numeral from '@elastic/numeral';
@ -44,7 +44,7 @@ function createSerializationHelper(
handlebars.registerHelper('json', createSerializationHelper('json', JSON.stringify));
handlebars.registerHelper(
'rison',
createSerializationHelper('rison', (v) => encode(v as RisonValue))
createSerializationHelper('rison', (v) => encode(v))
);
handlebars.registerHelper('date', (...args) => {

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { encode, RisonValue } from 'rison-node';
import { encode } from '@kbn/rison';
import Handlebars, { ExtendedCompileOptions, compileFnName } from '@kbn/handlebars';
import { i18n } from '@kbn/i18n';
import { emptyLabel } from '../../../../common/empty_label';
@ -41,7 +41,7 @@ function createSerializationHelper(
handlebars.registerHelper(
'rison',
createSerializationHelper('rison', (v) => encode(v as RisonValue))
createSerializationHelper('rison', (v) => encode(v))
);
handlebars.registerHelper('encodeURIComponent', (component: unknown) => {

View file

@ -10,7 +10,7 @@ import type { Serializable } from '@kbn/utility-types';
import { omitBy } from 'lodash';
import type { ParsedQuery } from 'query-string';
import { stringify } from 'query-string';
import rison from 'rison-node';
import rison from '@kbn/rison';
import { isFilterPinned } from '@kbn/es-query';
import { url } from '@kbn/kibana-utils-plugin/common';
import { GLOBAL_STATE_STORAGE_KEY, STATE_STORAGE_KEY, VisualizeConstants } from './constants';

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import rison from 'rison-node';
import rison from '@kbn/rison';
import { getUrl } from '@kbn/test';
import { FtrService } from '../ftr_provider_context';

View file

@ -540,6 +540,8 @@
"@kbn/repo-source-classifier/*": ["packages/kbn-repo-source-classifier/*"],
"@kbn/repo-source-classifier-cli": ["packages/kbn-repo-source-classifier-cli"],
"@kbn/repo-source-classifier-cli/*": ["packages/kbn-repo-source-classifier-cli/*"],
"@kbn/rison": ["packages/kbn-rison"],
"@kbn/rison/*": ["packages/kbn-rison/*"],
"@kbn/rule-data-utils": ["packages/kbn-rule-data-utils"],
"@kbn/rule-data-utils/*": ["packages/kbn-rule-data-utils/*"],
"@kbn/safer-lodash-set": ["packages/kbn-safer-lodash-set"],

View file

@ -1,28 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
declare module 'rison-node' {
export type RisonValue = undefined | null | boolean | number | string | RisonObject | RisonArray;
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface RisonArray extends Array<RisonValue> {}
export interface RisonObject {
[key: string]: RisonValue;
}
export const decode: (input: string) => RisonValue;
// eslint-disable-next-line @typescript-eslint/naming-convention
export const decode_object: (input: string) => RisonObject;
export const encode: <Input extends RisonValue>(input: Input) => string;
// eslint-disable-next-line @typescript-eslint/naming-convention
export const encode_object: <Input extends RisonObject>(input: Input) => string;
}

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison from 'rison-node';
import rison from '@kbn/rison';
import moment from 'moment';
import type { TimeRangeBounds } from '@kbn/data-plugin/common';

View file

@ -8,7 +8,7 @@
import React, { FC } from 'react';
import { parse, stringify } from 'query-string';
import { createContext, useCallback, useContext, useMemo } from 'react';
import { decode, encode } from 'rison-node';
import { decode, encode } from '@kbn/rison';
import { useHistory, useLocation } from 'react-router-dom';
import { isEqual } from 'lodash';

View file

@ -10,7 +10,7 @@ import { Location } from 'history';
import { IBasePath } from '@kbn/core/public';
import React from 'react';
import { useLocation } from 'react-router-dom';
import rison, { RisonValue } from 'rison-node';
import rison from '@kbn/rison';
import url from 'url';
import { APM_STATIC_DATA_VIEW_ID } from '../../../../../common/data_view_constants';
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
@ -53,7 +53,7 @@ export const getDiscoverHref = ({
const href = url.format({
pathname: basePath.prepend('/app/discover'),
hash: `/?_g=${rison.encode(risonQuery._g)}&_a=${rison.encode(
risonQuery._a as RisonValue
risonQuery._a
)}`,
});
return href;

View file

@ -6,7 +6,6 @@
*/
import { useEffect, useCallback, useMemo } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import type { RisonObject } from 'rison-node';
import { decodeQuery, encodeQuery } from '../navigation/query_utils';
/**
@ -35,7 +34,7 @@ export const useUrlQuery = <T extends object>(getDefaultQuery: () => T) => {
useEffect(() => {
if (search) return;
replace({ search: encodeQuery(getDefaultQuery() as RisonObject) });
replace({ search: encodeQuery(getDefaultQuery()) });
}, [getDefaultQuery, search, replace]);
return {

View file

@ -4,10 +4,10 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { encode, decode, type RisonObject } from 'rison-node';
import { encode, decode } from '@kbn/rison';
import type { LocationDescriptorObject } from 'history';
const encodeRison = (v: RisonObject): string | undefined => {
const encodeRison = (v: any): string | undefined => {
try {
return encode(v);
} catch (e) {
@ -27,7 +27,7 @@ const decodeRison = <T extends unknown>(query: string): T | undefined => {
const QUERY_PARAM_KEY = 'cspq';
export const encodeQuery = (query: RisonObject): LocationDescriptorObject['search'] => {
export const encodeQuery = (query: any): LocationDescriptorObject['search'] => {
const risonQuery = encodeRison(query);
if (!risonQuery) return;
return `${QUERY_PARAM_KEY}=${risonQuery}`;

View file

@ -16,7 +16,6 @@ import { TestProvider } from '../../../test/test_provider';
import { getFindingsQuery } from './use_latest_findings';
import { encodeQuery } from '../../../common/navigation/query_utils';
import { useLocation } from 'react-router-dom';
import { RisonObject } from 'rison-node';
import { buildEsQuery } from '@kbn/es-query';
import { getPaginationQuery } from '../utils/utils';
import { chartPluginMock } from '@kbn/charts-plugin/public/mocks';
@ -52,7 +51,7 @@ describe('<LatestFindingsContainer />', () => {
});
(useLocation as jest.Mock).mockReturnValue({
search: encodeQuery(query as unknown as RisonObject),
search: encodeQuery(query),
});
render(

View file

@ -7,7 +7,7 @@
import { parse } from 'query-string';
import { createContext, useCallback, useContext, useMemo } from 'react';
import { decode } from 'rison-node';
import { decode } from '@kbn/rison';
export interface Dictionary<TValue> {
[id: string]: TValue;

View file

@ -9,7 +9,7 @@ import React, { FC, useCallback, useEffect, useState } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import { parse, stringify } from 'query-string';
import { isEqual } from 'lodash';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import { SimpleSavedObject } from '@kbn/core/public';
import { i18n } from '@kbn/i18n';
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';

View file

@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import { stringify } from 'query-string';
import { SerializableRecord } from '@kbn/utility-types';
import { Filter, TimeRange } from '@kbn/es-query';

View file

@ -10,7 +10,7 @@ import { stringify } from 'querystring';
import React, { memo, useMemo, useState, useCallback, useEffect } from 'react';
import styled from 'styled-components';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import {
EuiFlexGroup,
EuiFlexItem,

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison from 'rison-node';
import rison from '@kbn/rison';
import { Workspace } from '../types';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison from 'rison-node';
import rison from '@kbn/rison';
import { i18n } from '@kbn/i18n';
import { Workspace } from '../types';

View file

@ -9,7 +9,7 @@ import actionCreatorFactory from 'typescript-fsa';
import { reducerWithInitialState } from 'typescript-fsa-reducers/dist';
import { i18n } from '@kbn/i18n';
import { modifyUrl } from '@kbn/std';
import rison from 'rison-node';
import rison from '@kbn/rison';
import { takeEvery } from 'redux-saga/effects';
import { format, parse } from 'url';
import { GraphState, GraphStoreDependencies } from './store';

View file

@ -6,7 +6,7 @@
*/
import { ALERT_RULE_PARAMETERS, TIMESTAMP } from '@kbn/rule-data-utils';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import { stringify } from 'query-string';
import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common/parse_technical_fields';

View file

@ -7,7 +7,7 @@
import React, { useState, useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import moment from 'moment';
import { useUiTracker, useLinkProps } from '@kbn/observability-plugin/public';

View file

@ -10,7 +10,7 @@ import type { Query } from '@kbn/es-query';
import moment from 'moment';
import { stringify } from 'query-string';
import React, { useCallback, useMemo } from 'react';
import { encode, RisonValue } from 'rison-node';
import { encode } from '@kbn/rison';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { MLJobsAwaitingNodeWarning } from '@kbn/ml-plugin/public';
import { useTrackPageview } from '@kbn/observability-plugin/public';
@ -112,7 +112,7 @@ export const LogEntryRateResultsContent: React.FunctionComponent<{
const params = {
logPosition: encode({
end: moment(timeRange.value.endTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
position: timeKey as RisonValue,
position: timeKey,
start: moment(timeRange.value.startTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
streamLive: false,
}),

View file

@ -7,7 +7,7 @@
import React, { useMemo, useCallback, useState } from 'react';
import moment from 'moment';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import { i18n } from '@kbn/i18n';
import { useMlHref, ML_PAGES } from '@kbn/ml-plugin/public';
import { euiStyled } from '@kbn/kibana-react-plugin/common';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import uuid from 'uuid';
import { set } from '@kbn/safer-lodash-set';
import { LinkDescriptor } from '@kbn/observability-plugin/public';

View file

@ -6,7 +6,7 @@
*/
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import {
FetchData,
FetchDataParams,

View file

@ -9,7 +9,7 @@ import { parse, stringify } from 'query-string';
import { History, Location } from 'history';
import React from 'react';
import { Route, RouteProps } from 'react-router-dom';
import { decode, encode, RisonValue } from 'rison-node';
import { decode, encode, RisonValue } from '@kbn/rison';
import { url } from '@kbn/kibana-utils-plugin/public';
import { throttle } from 'lodash';

View file

@ -8,7 +8,7 @@
import { parse, stringify } from 'query-string';
import { Location } from 'history';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { decode, encode, RisonValue } from 'rison-node';
import { decode, encode, RisonValue } from '@kbn/rison';
import { useHistory } from 'react-router-dom';
import { url } from '@kbn/kibana-utils-plugin/public';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison from 'rison-node';
import rison from '@kbn/rison';
import type { TimeRange } from '@kbn/data-plugin/common/query';
export const PLUGIN_ID = 'lens';

View file

@ -5,8 +5,7 @@
* 2.0.
*/
import type { RisonValue } from 'rison-node';
import rison from 'rison-node';
import rison from '@kbn/rison';
import { RENDER_AS } from './constants';
export function decodeMvtResponseBody(encodedRequestBody: string): object {
@ -18,7 +17,7 @@ export function encodeMvtResponseBody(unencodedRequestBody: object): string {
// encodeURIComponent does not encode '%'
// This causes preexisting '%' to break decoding because they are not valid URL encoding
// To prevent this, properly url encode '%' before calling encodeURIComponent
return encodeURIComponent(rison.encode(unencodedRequestBody as RisonValue).replace('%', '%25'));
return encodeURIComponent(rison.encode(unencodedRequestBody).replace('%', '%25'));
}
export function getAggsTileRequest({

View file

@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n';
import { Filter } from '@kbn/es-query';
import { ActionExecutionContext, Action } from '@kbn/ui-actions-plugin/public';
import { MultiPolygon, Polygon } from 'geojson';
import rison, { RisonObject } from 'rison-node';
import rison from '@kbn/rison';
import { URL_MAX_LENGTH } from '@kbn/core/public';
import { ACTION_GLOBAL_APPLY_FILTER } from '@kbn/unified-search-plugin/public';
import { buildGeoShapeFilter, PreIndexedShape } from '../../../../../common/elasticsearch_util';
@ -99,9 +99,7 @@ export class FeatureGeometryFilterForm extends Component<Props, State> {
// Ensure filter will not overflow URL. Filters that contain geometry can be extremely large.
// No elasticsearch support for pre-indexed shapes and geo_point spatial queries.
if (
window.location.href.length +
rison.encode(filter as unknown as RisonObject).length +
META_OVERHEAD >
window.location.href.length + rison.encode(filter).length + META_OVERHEAD >
URL_MAX_LENGTH
) {
this.setState({

View file

@ -7,7 +7,7 @@
/* eslint-disable max-classes-per-file */
import rison from 'rison-node';
import rison from '@kbn/rison';
import type { DataViewSpec } from '@kbn/data-views-plugin/public';
import type { SerializableRecord } from '@kbn/utility-types';
import { type Filter, isFilterPinned, type TimeRange, type Query } from '@kbn/es-query';
@ -97,13 +97,7 @@ export class MapsAppLocatorDefinition implements LocatorDefinition<MapsAppLocato
path = setStateToKbnUrl('_a', appState, { useHash }, path);
if (initialLayers && initialLayers.length) {
const risonEncodedInitialLayers = (
rison as unknown as {
encode_array: (
initialLayers: (LayerDescriptor[] & SerializableRecord) | undefined
) => string;
}
).encode_array(initialLayers);
const risonEncodedInitialLayers = rison.encodeArray(initialLayers);
path = `${path}&${INITIAL_LAYERS_KEY}=${encodeURIComponent(risonEncodedInitialLayers)}`;
}

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison from 'rison-node';
import rison from '@kbn/rison';
import { i18n } from '@kbn/i18n';
import '../../../classes/sources/wms_source';
import '../../../classes/sources/ems_file_source';
@ -13,26 +13,47 @@ import '../../../classes/sources/es_search_source';
import '../../../classes/sources/es_pew_pew_source';
import '../../../classes/sources/es_geo_grid_source';
import '../../../classes/sources/xyz_tms_source';
import { LayerDescriptor } from '../../../../common';
import { getToasts } from '../../../kibana_services';
import { INITIAL_LAYERS_KEY } from '../../../../common/constants';
export function getInitialLayersFromUrlParam() {
function isObj(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null;
}
function parseLayerDescriptors(mapInitLayers: string): LayerDescriptor[] {
const raw: any[] = rison.decodeArray(mapInitLayers);
return raw.flatMap((desc, i) => {
if (isObj(desc) && typeof desc.id === 'string') {
return desc as LayerDescriptor;
}
// we shouldn't end up here, but if we do it's likely only in testing or local dev so a console error is suitable
// eslint-disable-next-line no-console
console.error(`item ${i} in mapInitLayers is not a valid LayerDescriptor and was ignored`);
return [];
});
}
export function getInitialLayersFromUrlParam(): LayerDescriptor[] {
const locationSplit = window.location.href.split('?');
if (locationSplit.length <= 1) {
return [];
}
const mapAppParams = new URLSearchParams(locationSplit[1]);
if (!mapAppParams.has(INITIAL_LAYERS_KEY)) {
let mapInitLayers = mapAppParams.get(INITIAL_LAYERS_KEY);
if (!mapInitLayers) {
return [];
}
try {
let mapInitLayers = mapAppParams.get(INITIAL_LAYERS_KEY);
if (mapInitLayers![mapInitLayers!.length - 1] === '#') {
mapInitLayers = mapInitLayers!.substr(0, mapInitLayers!.length - 1);
// strip # from the end of the param
if (mapInitLayers.endsWith('#')) {
mapInitLayers = mapInitLayers.slice(0, -1);
}
// @ts-ignore
return rison.decode_array(mapInitLayers);
return parseLayerDescriptors(mapInitLayers);
} catch (e) {
getToasts().addWarning({
title: i18n.translate('xpack.maps.initialLayers.unableToParseTitle', {

View file

@ -7,7 +7,7 @@
import { cloneDeep } from 'lodash';
import moment from 'moment';
import rison, { RisonValue } from 'rison-node';
import rison, { RisonValue } from '@kbn/rison';
import React, { FC, useEffect, useMemo, useState } from 'react';
import { APP_ID as MAPS_APP_ID } from '@kbn/maps-plugin/common';
import {

View file

@ -7,7 +7,7 @@
import { TIME_RANGE_TYPE, URL_TYPE } from './constants';
import rison from 'rison-node';
import rison from '@kbn/rison';
import url from 'url';
import {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison from 'rison-node';
import rison from '@kbn/rison';
import type { Query } from '@kbn/es-query';
import { Filter } from '@kbn/es-query';
import type { LensSavedObjectAttributes } from '@kbn/lens-plugin/public';

View file

@ -9,7 +9,7 @@
import { get, flow } from 'lodash';
import moment from 'moment';
import rison, { RisonObject, RisonValue } from 'rison-node';
import rison, { type RisonValue } from '@kbn/rison';
import { parseInterval } from '../../../common/util/parse_interval';
import { escapeForElasticsearchQuery, replaceStringTokens } from './string_utils';
import {
@ -133,7 +133,7 @@ export function escapeForKQL(value: string | number): string {
type GetResultTokenValue = (v: string) => string;
export const isRisonObject = (value: RisonValue): value is RisonObject => {
export const isRisonObject = (value: RisonValue): value is Record<string, RisonValue> => {
return value !== null && typeof value === 'object';
};

View file

@ -16,7 +16,7 @@ import React, {
useEffect,
} from 'react';
import { isEqual } from 'lodash';
import { decode, encode } from 'rison-node';
import { decode, encode } from '@kbn/rison';
import { useHistory, useLocation } from 'react-router-dom';
import { BehaviorSubject, Observable } from 'rxjs';

View file

@ -7,7 +7,7 @@
import Boom from '@hapi/boom';
import { i18n } from '@kbn/i18n';
import rison from 'rison-node';
import rison from '@kbn/rison';
import { Duration } from 'moment/moment';
import { memoize } from 'lodash';
import {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison, { RisonValue } from 'rison-node';
import rison from '@kbn/rison';
import { URL_KEYS } from './constants/url_constants';
import type { ReportViewType, SeriesUrl } from '../types';
import type { AllSeries } from '../../../..';
@ -51,7 +51,7 @@ export function createExploratoryViewUrl(
return (
baseHref +
`/app/${appId}/exploratory-view/#?reportType=${reportType}&sr=${encodeUriIfNeeded(
rison.encode(allShortSeries as unknown as RisonValue)
rison.encode(allShortSeries)
)}`
);
}

View file

@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import rison, { RisonValue } from 'rison-node';
import rison from '@kbn/rison';
import {
buildQueryFilter,
PhraseFilter,
@ -29,7 +29,7 @@ export function createExploratoryViewRoutePath({
const allShortSeries: AllShortSeries = allSeries.map((series) => convertToShortUrl(series));
return `/exploratory-view/#?reportType=${reportType}&sr=${encodeUriIfNeeded(
rison.encode(allShortSeries as unknown as RisonValue)
rison.encode(allShortSeries)
)}`;
}

View file

@ -9,7 +9,7 @@ import { renderHook } from '@testing-library/react-hooks';
import { createMemoryHistory } from 'history';
import React, { PropsWithChildren } from 'react';
import { Router } from 'react-router-dom';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import { coreMock } from '@kbn/core/public/mocks';
import { CoreScopedHistory } from '@kbn/core/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';

View file

@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
import { EuiInMemoryTable, EuiCodeBlock, EuiToolTip, EuiButtonIcon } from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import { stringify } from 'querystring';
import { useKibana, isModifiedEvent, isLeftClickEvent } from '../common/lib/kibana';

View file

@ -7,7 +7,7 @@
import { i18n } from '@kbn/i18n';
import moment from 'moment';
import { stringify } from 'query-string';
import rison from 'rison-node';
import rison from '@kbn/rison';
import type { HttpFetchQuery } from '@kbn/core/public';
import { HttpSetup, IUiSettingsClient } from '@kbn/core/public';
import { buildKibanaPath } from '../../../common/build_kibana_path';

View file

@ -6,7 +6,7 @@
*/
import { schema } from '@kbn/config-schema';
import rison from 'rison-node';
import rison from '@kbn/rison';
import type { Logger } from '@kbn/core/server';
import type { ReportingCore } from '../..';
import { API_BASE_URL } from '../../../common/constants';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison from 'rison-node';
import rison from '@kbn/rison';
import { BehaviorSubject } from 'rxjs';
import { loggingSystemMock } from '@kbn/core/server/mocks';
import { setupServer } from '@kbn/core-test-helpers-test-utils';

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import type { RisonValue } from 'rison-node';
import { encode } from 'rison-node';
import type { RisonValue } from '@kbn/rison';
import { encode } from '@kbn/rison';
import { decodeRison, isRisonObject, isRegularString } from './rison_helpers';
export const entityToKql = (entityNames: string[], entity: string): string => {

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import type { RisonValue } from 'rison-node';
import { encode } from 'rison-node';
import type { RisonValue } from '@kbn/rison';
import { encode } from '@kbn/rison';
import { decodeRison, isRisonObject, isRegularString } from './rison_helpers';
export const operators = ['and', 'or', 'not'];

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import type { RisonValue } from 'rison-node';
import { encode } from 'rison-node';
import type { RisonValue } from '@kbn/rison';
import { encode } from '@kbn/rison';
import { decodeRison, isRisonObject, isRegularString } from './rison_helpers';
export const replacement = (match: string, p1: string, p2: string) => {

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import type { RisonValue, RisonObject } from 'rison-node';
import { decode } from 'rison-node';
import type { RisonValue } from '@kbn/rison';
import { decode } from '@kbn/rison';
import { isObject, isString } from 'lodash/fp';
export const decodeRison = (value: string): RisonValue => {
@ -17,7 +17,7 @@ export const decodeRison = (value: string): RisonValue => {
}
};
export const isRisonObject = (value: RisonValue): value is RisonObject => {
export const isRisonObject = (value: RisonValue): value is Record<string, RisonValue> => {
return isObject(value);
};

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { decode, encode } from 'rison-node';
import { decode, encode } from '@kbn/rison';
import type { ParsedQuery } from 'query-string';
import { parse, stringify } from 'query-string';
import { url } from '@kbn/kibana-utils-plugin/public';

View file

@ -9,7 +9,7 @@
import querystring from 'querystring';
import { createSelector } from 'reselect';
import { matchPath } from 'react-router-dom';
import { decode } from 'rison-node';
import { decode } from '@kbn/rison';
import type { Query } from '@kbn/es-query';
import type { Immutable, HostMetadata } from '../../../../../common/endpoint/types';
import { HostStatus } from '../../../../../common/endpoint/types';

View file

@ -7,8 +7,7 @@
import React, { memo, useCallback, useMemo } from 'react';
import { useHistory } from 'react-router-dom';
import type { RisonValue } from 'rison-node';
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import type { Query } from '@kbn/es-query';
import { TimeHistory } from '@kbn/data-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/public';
@ -37,9 +36,7 @@ export const AdminSearchBar = memo(() => {
// if query is changed, reset back to first page
// so that user is not (possibly) being left on an invalid page
page_index: params.query?.query === searchBarQuery.query ? queryParams.page_index : '0',
...(params.query?.query.trim()
? { admin_query: encode(params.query as unknown as RisonValue) }
: {}),
...(params.query?.query.trim() ? { admin_query: encode(params.query) } : {}),
})
);
},

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { decode } from 'rison-node';
import { decode } from '@kbn/rison';
import { isPanelViewAndParameters } from '../models/location_search';
import type { PanelViewAndParameters } from '../types';
import { parameterName } from './parameter_name';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import { createSelector } from 'reselect';
import type { PanelViewAndParameters, ResolverUIState } from '../../types';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import type { PanelViewAndParameters } from '../types';
/**

View file

@ -8,7 +8,7 @@
import React from 'react';
import url from 'url';
import { EuiButtonEmpty } from '@elastic/eui';
import rison, { RisonValue } from 'rison-node';
import rison from '@kbn/rison';
import { getMLJobId } from '../../../../../common/lib';
interface Props {
@ -42,8 +42,7 @@ export const getMLJobLinkHref = ({ basePath, monitorId, dateRange }: Props) => {
return url.format({
pathname: basePath + '/app/ml',
hash:
`${path}?_g=${rison.encode(query as RisonValue)}` +
(monitorId ? `&_a=${rison.encode(queryParams as RisonValue)}` : ''),
`${path}?_g=${rison.encode(query)}` + (monitorId ? `&_a=${rison.encode(queryParams)}` : ''),
});
};

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { encode } from 'rison-node';
import { encode } from '@kbn/rison';
import React, { FunctionComponent, useState, useEffect } from 'react';
import { buildPhrasesFilter, PhraseFilter } from '@kbn/es-query';

View file

@ -8,7 +8,7 @@
import { FlyoutOptionsUrlState } from '@kbn/infra-plugin/public/containers/logs/log_flyout';
import { LogPositionUrlState } from '@kbn/infra-plugin/public/containers/logs/log_position';
import querystring from 'querystring';
import { encode, RisonValue } from 'rison-node';
import { encode } from '@kbn/rison';
import { FtrProviderContext } from '../ftr_provider_context';
export interface TabsParams {
@ -37,7 +37,7 @@ export function InfraLogsPageProvider({ getPageObjects, getService }: FtrProvide
for (const key in params) {
if (params.hasOwnProperty(key)) {
const value = params[key] as unknown as RisonValue;
const value = params[key];
parsedParams[key] = encode(value);
}
}

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import rison, { RisonValue } from 'rison-node';
import rison from '@kbn/rison';
import {
API_GET_ILM_POLICY_STATUS,
API_MIGRATE_ILM_POLICY_URL,
@ -143,7 +143,7 @@ export function createScenarios({ getService }: Pick<FtrProviderContext, 'getSer
.send(job);
};
const generatePdf = async (username: string, password: string, job: JobParamsPDFDeprecated) => {
const jobParams = rison.encode(job as object as RisonValue);
const jobParams = rison.encode(job);
return await supertestWithoutAuth
.post(`/api/reporting/generate/printablePdf`)
.auth(username, password)
@ -151,7 +151,7 @@ export function createScenarios({ getService }: Pick<FtrProviderContext, 'getSer
.send({ jobParams });
};
const generatePng = async (username: string, password: string, job: JobParamsPNGDeprecated) => {
const jobParams = rison.encode(job as object as RisonValue);
const jobParams = rison.encode(job);
return await supertestWithoutAuth
.post(`/api/reporting/generate/png`)
.auth(username, password)
@ -163,7 +163,7 @@ export function createScenarios({ getService }: Pick<FtrProviderContext, 'getSer
username = 'elastic',
password = process.env.TEST_KIBANA_PASS || 'changeme'
) => {
const jobParams = rison.encode(job as object as RisonValue);
const jobParams = rison.encode(job);
return await supertestWithoutAuth
.post(`/api/reporting/generate/csv_searchsource`)

View file

@ -3785,6 +3785,10 @@
version "0.0.0"
uid ""
"@kbn/rison@link:bazel-bin/packages/kbn-rison":
version "0.0.0"
uid ""
"@kbn/rule-data-utils@link:bazel-bin/packages/kbn-rule-data-utils":
version "0.0.0"
uid ""