Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@json-layout/core

Package Overview
Dependencies
Maintainers
1
Versions
54
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@json-layout/core - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

4

package.json
{
"name": "@json-layout/core",
"version": "0.2.0",
"version": "0.3.0",
"description": "Compilation and state management utilities for JSON Layout.",

@@ -50,3 +50,3 @@ "type": "module",

"dependencies": {
"@json-layout/vocabulary": "^0.2.0",
"@json-layout/vocabulary": "^0.3.0",
"@types/markdown-it": "^13.0.1",

@@ -53,0 +53,0 @@ "ajv": "^8.12.0",

@@ -58,2 +58,9 @@ // import Debug from 'debug'

let defaultData
if ('default' in schema) defaultData = schema.default
else if (required) {
if (schema.type === 'object') defaultData = {}
if (schema.type === 'array') defaultData = []
}
const compObjects = isSwitchStruct(normalizedLayout) ? normalizedLayout.switch : [normalizedLayout]

@@ -63,2 +70,9 @@ for (const compObject of compObjects) {

if (compObject.if) pushExpression(expressions, compObject.if)
if ('const' in schema) compObject.constData = { type: 'js-eval', expr: JSON.stringify(schema.const) }
if (compObject.constData) pushExpression(expressions, compObject.constData)
if (defaultData && !compObject.defaultData) compObject.defaultData = { type: 'js-eval', expr: JSON.stringify(defaultData) }
if (compObject.defaultData) pushExpression(expressions, compObject.defaultData)
if (isItemsLayout(compObject) && compObject.getItems) {

@@ -75,14 +89,4 @@ if (isGetItemsExpression(compObject.getItems)) pushExpression(expressions, compObject.getItems)

let defaultData
if (schema.const) defaultData = schema.const
else if (schema.default) defaultData = schema.default
if (required) {
if (schema.type === 'object') defaultData = {} // TODO: this is only true if property is required ?
if (schema.type === 'array') defaultData = []
if (schema.type === 'string' && !schema.format) defaultData = ''
}
/** @type {import('./types.js').SkeletonNode} */
const node = { key: key ?? '', pointer, parentPointer, defaultData }
if (schema.const) node.const = schema.const
const node = { key: key ?? '', pointer, parentPointer }
if (schema.type === 'object') {

@@ -89,0 +93,0 @@ if (schema.properties) {

@@ -47,6 +47,4 @@ import type ajvModule from 'ajv'

parentPointer: string | null
defaultData?: unknown
const?: unknown
children?: SkeletonNode[] // optional children in the case of arrays and object nodes
childrenTrees?: SkeletonTree[] // other trees that can be instantiated with separate validation (for example in the case of new array items of oneOfs, etc)
}

@@ -10,3 +10,24 @@ /** @type {import('./types.js').LocaleMessages} */

sort: 'Sort',
showHelp: 'Show a help message'
up: 'Move up',
down: 'Move down',
showHelp: 'Show a help message',
mdeLink1: '[Link title',
mdeLink2: '](link url)',
mdeImg1: '![](',
mdeImg2: 'image url)',
mdeTable1: '',
mdeTable2: '\n\n| Column 1 | Column 2 | ColoColumnnne 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n',
bold: 'Bold',
italic: 'Italic',
heading: 'Title',
quote: 'Quote',
unorderedList: 'Unordered list',
orderedList: 'Ordered list',
createLink: 'Create a link',
insertImage: 'Insert an image',
createTable: 'Create a table',
preview: 'Aperçu du rendu',
mdeGuide: 'Documentation de la syntaxe',
undo: 'Undo',
redo: 'Redo'
}

@@ -10,3 +10,24 @@ /** @type {import('./types.js').LocaleMessages} */

sort: 'Trier',
showHelp: 'Afficher un message d\'aide'
up: 'Décaler vers le haut',
down: 'Décaler vers le bas',
showHelp: 'Afficher un message d\'aide',
mdeLink1: '[titre du lien',
mdeLink2: '](adresse du lien)',
mdeImg1: '![](',
mdeImg2: 'adresse de l\'image)',
mdeTable1: '',
mdeTable2: '\n\n| Colonne 1 | Colonne 2 | Colonne 3 |\n| -------- | -------- | -------- |\n| Texte | Texte | Texte |\n\n',
bold: 'Gras',
italic: 'Italique',
heading: 'Titre',
quote: 'Citation',
unorderedList: 'Liste à puce',
orderedList: 'Liste numérotée',
createLink: 'Créer un lien',
insertImage: 'Insérer une image',
createTable: 'Créer un tableau',
preview: 'Preview',
mdeGuide: 'Syntax documentation',
undo: 'Défaire',
redo: 'Refaire'
}

@@ -12,5 +12,26 @@ export interface CompileOptionsMessages {

sort: string
up: string
down: string
showHelp: string
mdeLink1: string
mdeLink2: string
mdeImg1: string
mdeImg2: string
mdeTable1: string
mdeTable2: string
bold: string
italic: string
heading: string
quote: string
unorderedList: string
orderedList: string
createLink: string
insertImage: string
createTable: string
preview: string
mdeGuide: string
undo: string
redo: string
}
export type LocaleMessages = CompileOptionsMessages & StateOptionsMessages

@@ -34,2 +34,3 @@ // eslint-disable-next-line import/no-named-default

* @typedef {import('./types.js').VerticalTabsNode} VerticalTabsNode
* @typedef {import('./types.js').StepperNode} StepperNode
* @typedef {import('./types.js').OneOfSelectNode} OneOfSelectNode

@@ -67,2 +68,4 @@ * @typedef {import('./types.js').ListNode} ListNode

initialValidation: 'withData',
defaultOn: 'empty',
autofocus: false,
...partialOptions,

@@ -174,8 +177,19 @@ messages

/**
* @private
* @type {string | null}
*/
_autofocusTarget
/**
* @private
* @type {string | null}
*/
_previousAutofocusTarget
/**
* @param {import("../index.js").CompiledLayout} compiledLayout
* @param {import("../index.js").SkeletonTree} skeletonTree
* @param {Partial<StatefulLayoutOptions>} options
* @param {unknown} data
* @param {unknown} [data]
*/
constructor (compiledLayout, skeletonTree, options, data = {}) {
constructor (compiledLayout, skeletonTree, options, data) {
this._compiledLayout = compiledLayout

@@ -186,2 +200,4 @@ this.skeletonTree = skeletonTree

this.prepareOptions(options)
this._autofocusTarget = this.options.autofocus ? '' : null
this._previousAutofocusTarget = null
this._data = data

@@ -191,2 +207,3 @@ this.initValidationState()

this.updateState()
this.handleAutofocus()
}

@@ -220,6 +237,7 @@

this.createStateTree()
if (this._data !== this._stateTree.root.data) {
if (this._data !== this._stateTree.root.data || this._autofocusTarget !== this._lastCreateStateTreeContext.autofocusTarget) {
logDataBinding('hydrating state tree changed the data, do it again', this._data, this._stateTree.root.data)
// this is necessary because a first hydration can add default values and change validity, etc
this._data = this._stateTree.root.data
this._autofocusTarget = this._lastCreateStateTreeContext.autofocusTarget
this.createStateTree()

@@ -236,3 +254,8 @@ }

/** @type {CreateStateTreeContext} */
const createStateTreeContext = { nodes: [], activeItems: this.activeItems }
const createStateTreeContext = {
nodes: [],
activeItems: this.activeItems,
autofocusTarget: this._autofocusTarget,
initial: !this._lastCreateStateTreeContext
}
this._stateTree = createStateTree(

@@ -250,3 +273,7 @@ createStateTreeContext,

if (!this.validationState.initialized) {
this.validationState = { initialized: true, validatedChildren: createStateTreeContext.nodes.filter(n => n.validated).map(n => n.fullKey) }
this._validationState = {
initialized: true,
validatedForm: this._validationState.validatedForm,
validatedChildren: createStateTreeContext.nodes.filter(n => n.validated).map(n => n.fullKey)
}
}

@@ -272,2 +299,9 @@ }

/**
* @returns {string[]}
*/
get errors () {
return this._lastCreateStateTreeContext.nodes.filter(n => !!n.error).map(n => /** @type {string} */(n.error))
}
/**
* @returns {boolean}

@@ -291,2 +325,3 @@ */

this.activeItems[node.fullKey] = activateKey
this._autofocusTarget = node.fullKey + '/' + activateKey
}

@@ -302,2 +337,6 @@ if (node.parentFullKey === null) {

this.input(parentNode, newParentValue)
if (activateKey !== undefined) {
this.handleAutofocus()
}
}

@@ -319,2 +358,14 @@

/**
* @param {StateNode} node
*/
validateNodeRecurse (node) {
this.validationState = { validatedChildren: this.validationState.validatedChildren.concat([node.fullKey]) }
if (node.children) {
for (const child of node.children) {
this.validateNodeRecurse(child)
}
}
}
/**
* @private

@@ -408,7 +459,9 @@ * @param {StateNode} node

this.activeItems[node.fullKey] = key
this._autofocusTarget = node.fullKey + '/' + key
if (node.key === '$oneOf') {
this.input(node, node.skeleton.childrenTrees?.[key].root.defaultData)
this.input(node, undefined)
} else {
this.updateState()
}
this.handleAutofocus()
}

@@ -423,2 +476,13 @@

}
handleAutofocus () {
const autofocusTarget = this._autofocusTarget
if (autofocusTarget !== null && this._autofocusTarget !== this._previousAutofocusTarget) {
this._previousAutofocusTarget = autofocusTarget
setTimeout(() => {
logDataBinding('emit autofocus event', autofocusTarget)
this.events.emit('autofocus', autofocusTarget)
})
}
}
}

@@ -1,2 +0,2 @@

import { isSwitchStruct, childIsCompObject, isCompositeLayout } from '@json-layout/vocabulary'
import { isSwitchStruct, childIsCompObject, isCompositeLayout, isFocusableLayout } from '@json-layout/vocabulary'
import { produce } from 'immer'

@@ -13,14 +13,21 @@ import { getChildDisplay } from './utils/display.js'

if (Array.isArray(data) && !data.length) return true
if (typeof data === 'object' && !Array.isArray(data) && !!data && Object.values(data).findIndex(prop => !isDataEmpty(prop)) === -1) return true
if (typeof data === 'object' && !Array.isArray(data) && !!data && Object.values(data).findIndex(prop => prop !== undefined) === -1) return true
return false
}
/**
* @param {unknown} data
* @param {import('@json-layout/vocabulary').CompObject} layout
* @param {import('./types.js').StatefulLayoutOptions} options
* @returns {boolean}
*/
const useDefaultData = (data, layout, options) => {
if (options.defaultOn === 'missing' && data === undefined) return true
if (options.defaultOn === 'empty' && isDataEmpty(data)) return true
return false
}
// use Immer for efficient updating with immutability and no-op detection
/** @type {(draft: import('./types.js').StateNode, key: string | number, fullKey: string, parentFullKey: string | null, dataPath: string, parentDataPath: string | null, skeleton: import('../index.js').SkeletonNode, layout: import('@json-layout/vocabulary').CompObject, cols: number, data: unknown, error: string | undefined, validated: boolean, options: import('./types.js').StatefulLayoutOptions, children: import('../index.js').StateNode[] | undefined) => import('../index.js').StateNode} */
const produceStateNode = produce((draft, key, fullKey, parentFullKey, dataPath, parentDataPath, skeleton, layout, cols, data, error, validated, options, children) => {
data = children && layout.comp !== 'list' ? produceStateNodeData(/** @type {Record<string, unknown>} */(data ?? {}), dataPath, children) : data
// empty data is removed and replaced by the default data
if (isDataEmpty(data) && skeleton.defaultData === undefined) data = undefined
data = skeleton.const ?? data ?? skeleton.defaultData
/** @type {(draft: import('./types.js').StateNode, key: string | number, fullKey: string, parentFullKey: string | null, dataPath: string, parentDataPath: string | null, skeleton: import('../index.js').SkeletonNode, layout: import('@json-layout/vocabulary').CompObject, cols: number, data: unknown, error: string | undefined, validated: boolean, options: import('./types.js').StatefulLayoutOptions, autofocus: boolean, children: import('../index.js').StateNode[] | undefined) => import('../index.js').StateNode} */
const produceStateNode = produce((draft, key, fullKey, parentFullKey, dataPath, parentDataPath, skeleton, layout, cols, data, error, validated, options, autofocus, children) => {
draft.messages = layout.messages ? produceStateNodeMessages(draft.messages || {}, layout.messages, options) : options.messages

@@ -41,2 +48,12 @@

draft.validated = validated
if (autofocus) {
draft.autofocus = true
delete draft.autofocusChild
} else {
delete draft.autofocus
const autofocusChild = children?.find(c => c.autofocus)
if (autofocusChild) draft.autofocusChild = autofocusChild.key
else delete draft.autofocusChild
}
draft.children = children

@@ -201,2 +218,6 @@ })

if (context.initial && parentOptions.autofocus && layout.autofocus) {
context.autofocusTarget = fullKey
}
/** @type {import('./types.js').StateNode[] | undefined} */

@@ -208,22 +229,29 @@ let children

const childrenOptions = produceCompositeChildrenOptions(options, layout)
children = layout.children.map((child, i) => {
const childSkeleton = skeleton.children?.find(c => c.key === child.key) ?? skeleton
const isSameData = typeof child.key === 'string' && child.key.startsWith('$')
return createStateNode(
children = []
let focusChild = context.autofocusTarget === fullKey
for (let i = 0; i < layout.children.length; i++) {
const childLayout = layout.children[i]
const childSkeleton = skeleton.children?.find(c => c.key === childLayout.key) ?? skeleton
const isSameData = typeof childLayout.key === 'string' && childLayout.key.startsWith('$')
const childFullKey = `${fullKey}/${childLayout.key}`
if (focusChild) context.autofocusTarget = childFullKey
const child = createStateNode(
context,
childrenOptions,
compiledLayout,
child.key,
`${fullKey}/${child.key}`,
childLayout.key,
childFullKey,
fullKey,
isSameData ? dataPath : `${dataPath}/${child.key}`,
isSameData ? dataPath : `${dataPath}/${childLayout.key}`,
dataPath,
childSkeleton,
child,
childLayout,
display,
isSameData ? objectData : objectData[child.key],
isSameData ? objectData : objectData[childLayout.key],
validationState,
reusedNode?.children?.[i]
)
})
if (child.autofocus || child.autofocusChild !== undefined) focusChild = false
children.push(child)
}
}

@@ -237,2 +265,4 @@

context.activeItems[fullKey] = activeChildTreeIndex
const activeChildKey = `${fullKey}/${activeChildTreeIndex}`
if (context.autofocusTarget === fullKey) context.autofocusTarget = activeChildKey
const activeChildTree = skeleton.childrenTrees[activeChildTreeIndex]

@@ -245,3 +275,3 @@ children = [

activeChildTreeIndex,
`${fullKey}/${activeChildTreeIndex}`,
activeChildKey,
fullKey,

@@ -265,5 +295,9 @@ dataPath,

const listItemOptions = layout.listEditMode === 'inline' ? options : produceReadonlyArrayItemOptions(options)
children = arrayData.map((itemData, i) => {
children = []
let focusChild = context.autofocusTarget === fullKey
for (let i = 0; i < arrayData.length; i++) {
const itemData = arrayData[i]
const childFullKey = `${fullKey}/${i}`
return createStateNode(
if (focusChild) context.autofocusTarget = childFullKey
const child = createStateNode(
context,

@@ -284,3 +318,5 @@ (layout.listEditMode === 'inline-single' && context.activeItems[fullKey] === i) ? options : listItemOptions,

)
})
if (child.autofocus || child.autofocusChild !== undefined) focusChild = false
children.push(child)
}
}

@@ -298,2 +334,25 @@

let nodeData = children ? produceStateNodeData(/** @type {Record<string, unknown>} */(data ?? {}), dataPath, children) : data
if (layout.constData) {
nodeData = evalExpression(compiledLayout.expressions, layout.constData, nodeData, options, display)
} else {
if (layout.defaultData && useDefaultData(nodeData, layout, options)) {
nodeData = evalExpression(compiledLayout.expressions, layout.defaultData, nodeData, options, display)
} else {
if (isDataEmpty(nodeData)) {
if (layout.nullable) {
// if a property is nullable empty values are converted to null
// except for undefined if we need to distinguish between empty and missing data
if (options.defaultOn !== 'missing' || nodeData !== undefined) {
nodeData = null
}
} else if (options.defaultOn !== 'missing') {
// remove empty data, except if we need to distinguish between empty and missing data
nodeData = undefined
}
}
}
}
const autofocus = isFocusableLayout(layout) && !options.readOnly && !options.summary && context.autofocusTarget === fullKey
const node = produceStateNode(

@@ -309,6 +368,7 @@ reusedNode ?? /** @type {import('./types.js').StateNode} */({}),

cols,
data,
nodeData,
error?.message,
validated,
options,
autofocus,
children && shallowCompareArrays(reusedNode?.children, children)

@@ -327,3 +387,2 @@ )

}
}
)
})

@@ -18,3 +18,3 @@ import { produce } from 'immer'

* @param {import('./utils/display.js').Display} display
* @param {unknown} value
* @param {unknown} data
* @param {import('./types.js').ValidationState} validationState

@@ -30,3 +30,3 @@ * @param {import('./types.js').StateTree} [reusedStateTree]

display,
value,
data,
validationState,

@@ -36,3 +36,3 @@ reusedStateTree

const validate = compiledLayout.validates[skeleton.root.pointer]
const valid = validate(value)
const valid = validate(data)
if (validate.errors) {

@@ -56,3 +56,3 @@ for (const error of validate.errors) {

display,
value,
data,
validationState,

@@ -59,0 +59,0 @@ reusedStateTree?.root

@@ -23,2 +23,3 @@ import { type ErrorObject } from 'ajv'

type ExpansionPanels,
type Stepper,
type List,

@@ -45,2 +46,4 @@ type Combobox

messages: LocaleMessages
autofocus?: boolean
autofocusChild?: string | number
children?: StateNode[]

@@ -59,2 +62,4 @@ }

activeItems: Record<string, number>
autofocusTarget: string | null
initial: boolean
}

@@ -73,2 +78,3 @@

'update': StatefulLayout
autofocus: string
}

@@ -81,3 +87,5 @@

initialValidation: 'never' | 'always' | 'withData'
defaultOn: 'missing' | 'empty' | 'never'
messages: LocaleMessages
autofocus: boolean
}

@@ -119,4 +127,6 @@

export type StepperNode = StateNode & { layout: Stepper, children: StateNode[] }
export type ListNode = StateNode & { layout: List, data: any[], children: StateNode[], childrenTrees: SkeletonTree[] }
export type ComboboxNode = Omit<StateNode, 'children'> & { layout: Combobox, data: any[] }

@@ -39,4 +39,2 @@ import type ajvModule from 'ajv';

parentPointer: string | null;
defaultData?: unknown;
const?: unknown;
children?: SkeletonNode[];

@@ -43,0 +41,0 @@ childrenTrees?: SkeletonTree[];

@@ -11,5 +11,26 @@ export interface CompileOptionsMessages {

sort: string;
up: string;
down: string;
showHelp: string;
mdeLink1: string;
mdeLink2: string;
mdeImg1: string;
mdeImg2: string;
mdeTable1: string;
mdeTable2: string;
bold: string;
italic: string;
heading: string;
quote: string;
unorderedList: string;
orderedList: string;
createLink: string;
insertImage: string;
createTable: string;
preview: string;
mdeGuide: string;
undo: string;
redo: string;
}
export type LocaleMessages = CompileOptionsMessages & StateOptionsMessages;
//# sourceMappingURL=types.d.ts.map

@@ -25,2 +25,3 @@ export { Display } from "./utils/display.js";

* @typedef {import('./types.js').VerticalTabsNode} VerticalTabsNode
* @typedef {import('./types.js').StepperNode} StepperNode
* @typedef {import('./types.js').OneOfSelectNode} OneOfSelectNode

@@ -38,3 +39,3 @@ * @typedef {import('./types.js').ListNode} ListNode

* @param {Partial<StatefulLayoutOptions>} options
* @param {unknown} data
* @param {unknown} [data]
*/

@@ -111,2 +112,12 @@ constructor(compiledLayout: import("../index.js").CompiledLayout, skeletonTree: import("../index.js").SkeletonTree, options: Partial<StatefulLayoutOptions>, data?: unknown);

/**
* @private
* @type {string | null}
*/
private _autofocusTarget;
/**
* @private
* @type {string | null}
*/
private _previousAutofocusTarget;
/**
* @type {Record<string, number>}

@@ -139,2 +150,6 @@ */

/**
* @returns {string[]}
*/
get errors(): string[];
/**
* @returns {boolean}

@@ -154,2 +169,6 @@ */

/**
* @param {StateNode} node
*/
validateNodeRecurse(node: StateNode): void;
/**
* @private

@@ -176,2 +195,3 @@ * @param {StateNode} node

deactivateItem(node: StateNode): void;
handleAutofocus(): void;
}

@@ -200,2 +220,3 @@ export type StateNode = import('./types.js').StateNode;

export type VerticalTabsNode = import('./types.js').VerticalTabsNode;
export type StepperNode = import('./types.js').StepperNode;
export type OneOfSelectNode = import('./types.js').OneOfSelectNode;

@@ -202,0 +223,0 @@ export type ListNode = import('./types.js').ListNode;

@@ -7,3 +7,3 @@ /**

* @param {import('./utils/display.js').Display} display
* @param {unknown} value
* @param {unknown} data
* @param {import('./types.js').ValidationState} validationState

@@ -13,3 +13,3 @@ * @param {import('./types.js').StateTree} [reusedStateTree]

*/
export function createStateTree(context: import('./types.js').CreateStateTreeContext, options: import('./types.js').StatefulLayoutOptions, compiledLayout: import('../index.js').CompiledLayout, skeleton: import('../index.js').SkeletonTree, display: import('./utils/display.js').Display, value: unknown, validationState: import('./types.js').ValidationState, reusedStateTree?: import("./types.js").StateTree | undefined): import('./types.js').StateTree;
export function createStateTree(context: import('./types.js').CreateStateTreeContext, options: import('./types.js').StatefulLayoutOptions, compiledLayout: import('../index.js').CompiledLayout, skeleton: import('../index.js').SkeletonTree, display: import('./utils/display.js').Display, data: unknown, validationState: import('./types.js').ValidationState, reusedStateTree?: import("./types.js").StateTree | undefined): import('./types.js').StateTree;
//# sourceMappingURL=state-tree.d.ts.map
import { type ErrorObject } from 'ajv';
import { type CompObject, type Cols, type StateNodeOptions, type TextField, type Textarea, type NumberField, type Slider, type Checkbox, type Switch, type DatePicker, type DateTimePicker, type TimePicker, type ColorPicker, type Section, type OneOfSelect, type Select, type Autocomplete, type Tabs, type VerticalTabs, type ExpansionPanels, type List, type Combobox } from '@json-layout/vocabulary';
import { type CompObject, type Cols, type StateNodeOptions, type TextField, type Textarea, type NumberField, type Slider, type Checkbox, type Switch, type DatePicker, type DateTimePicker, type TimePicker, type ColorPicker, type Section, type OneOfSelect, type Select, type Autocomplete, type Tabs, type VerticalTabs, type ExpansionPanels, type Stepper, type List, type Combobox } from '@json-layout/vocabulary';
import { type SkeletonTree, type SkeletonNode, type StatefulLayout } from '../index.js';

@@ -20,2 +20,4 @@ import { type LocaleMessages } from '../i18n/types.js';

messages: LocaleMessages;
autofocus?: boolean;
autofocusChild?: string | number;
children?: StateNode[];

@@ -32,2 +34,4 @@ }

activeItems: Record<string, number>;
autofocusTarget: string | null;
initial: boolean;
}

@@ -42,2 +46,3 @@ export interface ValidationState {

'update': StatefulLayout;
autofocus: string;
};

@@ -49,3 +54,5 @@ export type StatefulLayoutOptions = Required<StateNodeOptions> & {

initialValidation: 'never' | 'always' | 'withData';
defaultOn: 'missing' | 'empty' | 'never';
messages: LocaleMessages;
autofocus: boolean;
};

@@ -121,2 +128,6 @@ export type TextFieldNode = Omit<StateNode, 'children'> & {

};
export type StepperNode = StateNode & {
layout: Stepper;
children: StateNode[];
};
export type ListNode = StateNode & {

@@ -123,0 +134,0 @@ layout: List;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc