├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── main.yml ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc.json ├── .yarnrc.yml ├── demo ├── customfield.gif ├── custommanager-transparent.gif ├── overview-transparent.gif ├── overview.gif ├── packagejson-transparent.gif └── packagejson.gif ├── next-releasenotes.md ├── package.json ├── readme.md ├── src ├── DescriptionRenderer.tsx ├── Form.tsx ├── FormFieldRenderer.tsx ├── FormHeader.tsx ├── NumberFieldRenderer.tsx ├── SubmitButton.tsx ├── canSubmit.ts ├── demo │ ├── custommanager.tsx │ ├── imperative.ts │ ├── overview.tsx │ └── packagejson.tsx ├── imperativeInterface.tsx ├── index.ts ├── managers │ ├── BooleanFormFieldManager.tsx │ ├── FloatFormFieldManager.tsx │ ├── IntegerFormFieldManager.tsx │ ├── SelectFormFieldManager.tsx │ ├── StringFormFieldManager.tsx │ └── managers.ts └── types.ts ├── tsconfig.json └── yarn.lock /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: lukasbach 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | **Expected behavior** 16 | A clear and concise description of what you expected to happen. 17 | 18 | **Screenshots** 19 | If applicable, add screenshots to help explain your problem. 20 | 21 | **Additional context** 22 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Docs Deployment 2 | on: push 3 | jobs: 4 | build-and-deploy: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout 🛎️ 8 | uses: actions/checkout@v2.3.1 9 | with: 10 | persist-credentials: false 11 | - name: Install and Build 🔧 12 | run: | # Install npm packages and build the docs 13 | yarn 14 | yarn build 15 | yarn build:docs 16 | - name: Deploy 🚀 17 | uses: JamesIves/github-pages-deploy-action@3.6.2 18 | with: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | BRANCH: gh-pages 21 | FOLDER: docs 22 | CLEAN: true 23 | SINGLE_COMMIT: true 24 | # TARGET_FOLDER: docs # The folder that we serve our Storybook files 25 | GIT_CONFIG_NAME: lukasbachbot 26 | GIT_CONFIG_EMAIL: bot@noreply.lukasbach.com 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | lib 4 | docs 5 | .yarn -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib/demo 2 | src 3 | node_modules 4 | .idea 5 | demo 6 | docs -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .github 3 | demo 4 | docs 5 | lib 6 | node_modules 7 | next-releasenotes.md -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "bracketSpacing": true, 4 | "printWidth": 120, 5 | "semi": true, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "arrowParens": "avoid", 10 | "endOfLine": "lf", 11 | "trailingComma": "es5" 12 | } 13 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /demo/customfield.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasbach/ink-form/af553b24a716cc78a59232e2d6a1acd4b5ecc783/demo/customfield.gif -------------------------------------------------------------------------------- /demo/custommanager-transparent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasbach/ink-form/af553b24a716cc78a59232e2d6a1acd4b5ecc783/demo/custommanager-transparent.gif -------------------------------------------------------------------------------- /demo/overview-transparent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasbach/ink-form/af553b24a716cc78a59232e2d6a1acd4b5ecc783/demo/overview-transparent.gif -------------------------------------------------------------------------------- /demo/overview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasbach/ink-form/af553b24a716cc78a59232e2d6a1acd4b5ecc783/demo/overview.gif -------------------------------------------------------------------------------- /demo/packagejson-transparent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasbach/ink-form/af553b24a716cc78a59232e2d6a1acd4b5ecc783/demo/packagejson-transparent.gif -------------------------------------------------------------------------------- /demo/packagejson.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasbach/ink-form/af553b24a716cc78a59232e2d6a1acd4b5ecc783/demo/packagejson.gif -------------------------------------------------------------------------------- /next-releasenotes.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasbach/ink-form/af553b24a716cc78a59232e2d6a1acd4b5ecc783/next-releasenotes.md -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ink-form", 3 | "type": "module", 4 | "version": "2.0.1", 5 | "description": "Complex user-friendly form component for React Ink", 6 | "main": "lib/index.js", 7 | "exports": "./lib/index.js", 8 | "types": "lib/index.d.ts", 9 | "keywords": [ 10 | "react", 11 | "cli", 12 | "ui", 13 | "component", 14 | "input", 15 | "forms", 16 | "reusable", 17 | "ink", 18 | "commandline", 19 | "cmd" 20 | ], 21 | "repository": "https://github.com/lukasbach/ink-form", 22 | "author": "Lukas Bach ", 23 | "license": "MIT", 24 | "bugs": "https://github.com/lukasbach/ink-form/issues", 25 | "devDependencies": { 26 | "@types/node": "^14.14.45", 27 | "@types/react": "^18.2.41", 28 | "ink": "^4.4.1", 29 | "prettier": "^2.2.1", 30 | "publish-fast": "^0.0.20", 31 | "react": "^18.2.0", 32 | "ts-node": "^10.9.1", 33 | "typedoc": "^0.25.4", 34 | "typescript": "^5.3.2" 35 | }, 36 | "scripts": { 37 | "start": "ts-node-esm src/demo/overview.tsx", 38 | "demo:overview": "ts-node-esm src/demo/overview.tsx", 39 | "demo:packagejson": "ts-node-esm src/demo/packagejson.tsx", 40 | "demo:custommanager": "ts-node-esm src/demo/custommanager.tsx", 41 | "demo:imperative": "ts-node-esm src/demo/imperative.ts", 42 | "build": "tsc", 43 | "build:docs": "typedoc --out docs src/index.ts", 44 | "lint": "prettier --check .", 45 | "prettier:check": "prettier --check .", 46 | "prettier:write": "prettier --write .", 47 | "release": "publish-fast" 48 | }, 49 | "peerDependencies": { 50 | "ink": ">=4", 51 | "react": ">=18" 52 | }, 53 | "dependencies": { 54 | "ink-select-input": "^5.0.0", 55 | "ink-text-input": "^6.0.0" 56 | }, 57 | "publishConfig": { 58 | "access": "public" 59 | }, 60 | "publish": { 61 | "preScripts": "build,build:docs,lint", 62 | "releaseNotesSource": "next-releasenotes.md" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ink-form 2 | 3 | `ink-form` is a Node library for displaying a user-friendly form in a terminal window. 4 | It can be used in two ways, either by using the React Ink component `Form` exported by 5 | the package, or by using the imperative API `openForm(options)`. 6 | 7 | ![alt text](https://github.com/lukasbach/ink-form/raw/main/demo/overview.gif 'Demo 1') 8 | ![alt text](https://github.com/lukasbach/ink-form/raw/main/demo/packagejson.gif 'Demo 2') 9 | 10 | ## Example usage 11 | 12 | npm install ink-form react ink 13 | 14 | ```typescript jsx 15 | const options = [ 16 | { label: 'Opt 1', value: 'a' }, 17 | { label: 'Opt 2', value: 'b' }, 18 | ]; 19 | 20 | const form: FormProps = { 21 | form: { 22 | title: 'Form title', 23 | sections: [ 24 | { 25 | title: 'Text and Number fields', 26 | fields: [ 27 | { type: 'string', name: 'field1', label: 'Input with initial value', initialValue: 'Initial value' }, 28 | { type: 'string', name: 'field2', label: 'Masked input', mask: '*' }, 29 | { type: 'integer', name: 'field3', label: 'Integer between -5 and 8, stepsize 2', min: -5, max: 8, step: 2 }, 30 | { type: 'float', name: 'field4', label: 'Float between 0 and 5, stepsize 0.1', min: 0, max: 5, step: 0.1 }, 31 | ], 32 | }, 33 | { 34 | title: 'Select and boolean fields', 35 | fields: [ 36 | { type: 'select', name: 'field5', label: 'Select', options }, 37 | { type: 'multiselect', name: 'field6', label: 'Multi Select', options }, 38 | { type: 'boolean', name: 'field7', label: 'Boolean select', options }, 39 | ], 40 | }, 41 | ], 42 | }, 43 | }; 44 | 45 | // either: 46 | (async () => { 47 | const result = await openForm(form); 48 | console.log(`Finished with value`, result); 49 | })(); 50 | 51 | // or: 52 | render( 53 |
{ 56 | console.log(`Finished with value`, result); 57 | }} 58 | /> 59 | ); 60 | ``` 61 | 62 | If you want to see how using `ink-form` feels, you can clone this repo, run `yarn` to install 63 | dependencies and then run one of the demo scripts: 64 | 65 | - `yarn demo:overview` ([See Code](https://github.com/lukasbach/ink-form/blob/main/src/demo/overview.tsx)) 66 | - `yarn demo:packagejson` ([See Code](https://github.com/lukasbach/ink-form/blob/main/src/demo/packagejson.tsx)) 67 | - `yarn demo:custommanager` ([See Code](https://github.com/lukasbach/ink-form/blob/main/src/demo/custommanager.tsx)) 68 | - `yarn demo:imperative` ([See Code](https://github.com/lukasbach/ink-form/blob/main/src/demo/imperative.ts)) 69 | 70 | ## Update Note 71 | 72 | This package is now pure ESM as of 2.0.0. (Details: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) 73 | 74 | With that upgrade, I had to remove the multi select component as its dependency does not support ESM. Please 75 | use the v1x version branch with CJS if you need that. 76 | 77 | ## Documentation 78 | 79 | Detailed documentation is available at [lukasbach.github.io/ink-form](https://lukasbach.github.io/ink-form/). 80 | Install the package with `npm install ink-form --save` or `yarn add ink-form` to your project. 81 | 82 | Then, render the form by invoking the [imperative interface](https://lukasbach.github.io/ink-form/modules.html#openform) 83 | or by rendering the [React Ink component](https://lukasbach.github.io/ink-form/modules.html#form). 84 | Both take [`FormProps`](https://lukasbach.github.io/ink-form/interfaces/formprops.html) as parameters. 85 | 86 | The most important property is the `form`-property, which dictates how the form fields are structured. It follows 87 | the [`FormStructure`](https://lukasbach.github.io/ink-form/interfaces/formstructure.html)-interface. Look into the 88 | example above to see an example. 89 | 90 | ## Custom fields 91 | 92 | A form field describes a type of input, i.e. text input, number input etc. 93 | Included are: 94 | 95 | - FormFieldString 96 | - FormFieldInteger 97 | - FormFieldFloat 98 | - FormFieldSelect 99 | - FormFieldMultiSelect 100 | - FormFieldBoolean 101 | 102 | You can add your own form field by extending 103 | [`AbstractFormField`](https://lukasbach.github.io/ink-form/modules.html#abstractformfield) 104 | and implementing an associated 105 | [`FormFieldManager`](https://lukasbach.github.io/ink-form/interfaces/formfieldmanager.html). 106 | 107 | ![alt text](https://github.com/lukasbach/ink-form/raw/main/demo/customfield.gif 'Demo 3') 108 | -------------------------------------------------------------------------------- /src/DescriptionRenderer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Description } from './types.js'; 3 | import { Box, Text } from 'ink'; 4 | 5 | export const DescriptionRenderer: React.FC<{ description: Description }> = props => { 6 | if (!props.description) { 7 | return null; 8 | } else if ((props.description as JSX.Element).type) { 9 | return props.description as JSX.Element; 10 | } else if (Array.isArray(props.description)) { 11 | return ( 12 | 13 | {props.description.map(line => ( 14 | 15 | {line} 16 | 17 | ))} 18 | 19 | ); 20 | } else { 21 | return {props.description}; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/Form.tsx: -------------------------------------------------------------------------------- 1 | import { Box, useFocusManager, useInput } from 'ink'; 2 | import { useEffect, useMemo, useState } from 'react'; 3 | import * as React from 'react'; 4 | import { FormProps } from './types.js'; 5 | import { FormHeader } from './FormHeader.js'; 6 | import { FormFieldRenderer } from './FormFieldRenderer.js'; 7 | import { DescriptionRenderer } from './DescriptionRenderer.js'; 8 | import { canSubmit } from './canSubmit.js'; 9 | import { SubmitButton } from './SubmitButton.js'; 10 | 11 | export const Form: React.FC = props => { 12 | const isControlled = props.value !== undefined; 13 | const [currentTab, setCurrentTab] = useState(0); 14 | const [value, setValue] = useState(props.value ?? {}); 15 | const [editingField, setEditingField] = useState(); 16 | const canSubmitForm = useMemo(() => canSubmit(props.form, value), [value, props.form]); 17 | const focusManager = useFocusManager(); 18 | 19 | useEffect(() => { 20 | focusManager.enableFocus(); 21 | }, []); 22 | 23 | useEffect(() => { 24 | if (props.value) { 25 | setValue(props.value); 26 | } 27 | }, [props.value]); 28 | 29 | useEffect(() => { 30 | // Set initial values 31 | if (!isControlled) { 32 | setValueAndPropagate({ 33 | ...value, 34 | ...props.form.sections 35 | .map(section => 36 | section.fields 37 | .map(field => (field.initialValue !== undefined ? { [field.name]: field.initialValue } : {})) 38 | .reduce((obj1, obj2) => ({ ...obj1, ...obj2 }), {}) 39 | ) 40 | .reduce((obj1, obj2) => ({ ...obj1, ...obj2 }), {}), 41 | }); 42 | } 43 | }, []); 44 | 45 | const setValueAndPropagate = (value: object) => { 46 | setValue(value); 47 | props.onChange?.(value); 48 | }; 49 | 50 | useInput( 51 | (input, key) => { 52 | if (key.upArrow) { 53 | focusManager.focusPrevious(); 54 | } else if (key.downArrow) { 55 | focusManager.focusNext(); 56 | } 57 | }, 58 | { isActive: !editingField } 59 | ); 60 | 61 | return ( 62 | 63 | 64 | {!editingField && props.form.sections[currentTab].description && ( 65 | 66 | 67 | 68 | )} 69 | 70 | {currentTab > props.form.sections.length - 1 71 | ? null 72 | : props.form.sections[currentTab].fields.map(field => ( 73 | setValueAndPropagate({ ...value, [field.name]: v })} 79 | onSetEditingField={setEditingField} 80 | editingField={editingField} 81 | customManagers={props.customManagers} 82 | /> 83 | ))} 84 | 85 | {!editingField && ( 86 | 87 | props.onSubmit?.(value)} /> 88 | 89 | )} 90 | 91 | ); 92 | }; 93 | -------------------------------------------------------------------------------- /src/FormFieldRenderer.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { FormField, FormFieldRendererProps, SpecificFormFieldRendererProps } from './types.js'; 3 | import { Box, useFocus, Text, useInput } from 'ink'; 4 | import { getManager } from './managers/managers.js'; 5 | import { DescriptionRenderer } from './DescriptionRenderer.js'; 6 | 7 | export const FormFieldRenderer: React.FC> = props => { 8 | const manager = getManager(props.field.type, props.customManagers); 9 | const [error, setError] = useState(); 10 | const [currentValue, setCurrentValue] = useState(props.value ?? props.field.initialValue); 11 | 12 | const isEditing = !!props.editingField && props.editingField === (props.field.label ?? props.field.name); 13 | const hide = !isEditing && !!props.editingField; 14 | 15 | const save = (newValue?: any) => { 16 | if (!error) { 17 | if (newValue) { 18 | props.onChange(newValue); 19 | setCurrentValue(newValue); 20 | } else { 21 | props.onChange(currentValue); 22 | } 23 | props.onSetEditingField(undefined); 24 | } 25 | }; 26 | 27 | const cancel = () => { 28 | setCurrentValue(props.value); 29 | props.onSetEditingField(undefined); 30 | setError(undefined); 31 | }; 32 | 33 | const { isFocused } = useFocus({}); 34 | 35 | useInput( 36 | (input, key) => { 37 | if (!isEditing && key.return && !key.ctrl && !key.meta) { 38 | props.onSetEditingField(props.field.label ?? props.field.name); 39 | } else if (isEditing && key.escape) { 40 | cancel(); 41 | } else if (isEditing && key.return && (!manager?.needCtrlToReturnSave || key.ctrl)) { 42 | save(); 43 | } 44 | }, 45 | { isActive: isFocused } 46 | ); 47 | 48 | if (hide) { 49 | return null; 50 | } 51 | 52 | if (!isEditing) { 53 | const RenderValue = manager?.renderValue ?? (() => <>{props.value}); 54 | return ( 55 | 56 | 57 | 58 | {props.field.label ?? props.field.name} 59 | 60 | {props.field.required && *} 61 | : 62 | 63 | 64 | 65 | 66 | {isFocused && ( 67 | 68 | Press enter to edit 69 | 70 | )} 71 | 72 | ); 73 | } else { 74 | let component: JSX.Element; 75 | const rendererProps: SpecificFormFieldRendererProps = { 76 | ...props, 77 | onError: setError, 78 | onClearError: () => setError(undefined), 79 | onChange: setCurrentValue, 80 | value: currentValue, 81 | onSave: save, 82 | onCancel: cancel, 83 | error, 84 | }; 85 | 86 | if (!manager) { 87 | component = No formfield manager for form field of type {props.field.type} available.; 88 | } else { 89 | const Field = manager.renderField; 90 | component = ; 91 | } 92 | 93 | return ( 94 | 95 | 96 | {props.field.label ?? props.field.name} 97 | {props.field.required && *} 98 | : 99 | 100 | {component} 101 | {props.field.description && ( 102 | 103 | 104 | 105 | 106 | 107 | )} 108 | {error && ( 109 | 110 | Error: {error} 111 | 112 | )} 113 | 114 | 115 | {error ? ( 116 | <>Press ESC to cancel. 117 | ) : ( 118 | <>Press {manager?.needCtrlToReturnSave ? 'CTRL+Enter' : 'Enter'} to complete field, or ESC to cancel. 119 | )} 120 | 121 | 122 | 123 | ); 124 | } 125 | }; 126 | -------------------------------------------------------------------------------- /src/FormHeader.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Box, Text, useInput } from 'ink'; 3 | import { FormProps } from './types.js'; 4 | 5 | export const HELP_SECTION_ID = 'Help'; 6 | 7 | export const FormHeader: React.FC< 8 | FormProps & { currentTab: number; onChangeTab: (tab: number) => void; editingField?: string } 9 | > = props => { 10 | const sections = props.form.sections; 11 | 12 | useInput( 13 | (input, key) => { 14 | let id: undefined | number = undefined; 15 | 16 | if (key.rightArrow) { 17 | id = props.currentTab + 1; 18 | } else if (key.leftArrow) { 19 | id = props.currentTab - 1; 20 | } else if (/\d/.test(input)) { 21 | id = parseInt(input) - 1; 22 | } 23 | 24 | if (id !== undefined && id >= 0 && id < sections.length) { 25 | props.onChangeTab(id); 26 | } 27 | }, 28 | { isActive: !props.editingField } 29 | ); 30 | 31 | return ( 32 | 33 | 34 | 35 | {props.form.title} 36 | 37 | 38 | 39 | {!props.editingField ? 'Use arrow keys to move around' : 'Press ESC to cancel, or Enter to complete field'} 40 | 41 | 42 | 43 | 44 | 45 | {!props.editingField ? ( 46 | sections.map((section, id) => ( 47 | 48 | [{id + 1}] 49 | 50 | {section.title} 51 | 52 | 53 | 54 | )) 55 | ) : ( 56 | 57 | Editing {props.editingField} 58 | 59 | )} 60 | 61 | 62 | 63 | ); 64 | }; 65 | -------------------------------------------------------------------------------- /src/NumberFieldRenderer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { FormFieldFloat, FormFieldInteger, SpecificFormFieldRendererProps } from './types.js'; 3 | import { Box, Text, useInput } from 'ink'; 4 | import TextInput from 'ink-text-input'; 5 | 6 | const FLOAT_REGEX = /^-?((\d+)|(\d*\.\d+))$/; 7 | const INTEGER_REGEX = /^-?\d+$/; 8 | 9 | export const NumberFieldRenderer: React.FC< 10 | SpecificFormFieldRendererProps & { isFloat: boolean } 11 | > = props => { 12 | const regex = props.isFloat ? FLOAT_REGEX : INTEGER_REGEX; 13 | const parse = props.isFloat ? parseFloat : parseInt; 14 | 15 | const change = (value: string) => { 16 | if (regex.test(value)) { 17 | props.onClearError(); 18 | const asNumber = Math.round(parse(value) * 100000) / 100000; 19 | if (props.field.min !== undefined && props.field.min > asNumber) { 20 | props.onError(`"${value}" too small, must be above or equal to ${props.field.min}.`); 21 | props.onChange(value as any); 22 | return; 23 | } else if (props.field.max !== undefined && props.field.max < asNumber) { 24 | props.onError(`"${value}" too big, must be below or equal to ${props.field.max}.`); 25 | props.onChange(value as any); 26 | return; 27 | } else { 28 | props.onChange(asNumber); 29 | } 30 | } else { 31 | props.onError(`"${value}" is not an ${props.isFloat ? 'float' : 'integer'}.`); 32 | props.onChange(value as any); 33 | } 34 | }; 35 | 36 | useInput((input, key) => { 37 | if (typeof props.value === 'number') { 38 | if (key.upArrow) { 39 | change('' + ((props.value ?? 0) + (props.field.step ?? 1))); 40 | } else if (key.downArrow) { 41 | change('' + ((props.value ?? 0) - (props.field.step ?? 1))); 42 | } 43 | } else { 44 | if (key.upArrow || key.downArrow) { 45 | change( 46 | '' + ((props.field.min ?? 0) <= 0 && (props.field.max ?? 0) >= 0 ? 0 : props.field.min ?? props.field.max) 47 | ); 48 | } 49 | } 50 | }); 51 | 52 | return ( 53 | 54 | 55 | { 58 | if (regex.test(value)) { 59 | props.onClearError(); 60 | change(value); 61 | } else { 62 | props.onError(`"${value}" is not an ${props.isFloat ? 'float' : 'integer'}.`); 63 | props.onChange(value as any); 64 | } 65 | }} 66 | placeholder={props.field.placeholder} 67 | onSubmit={() => props.onSetEditingField(undefined)} 68 | /> 69 | 70 | 71 | Press UP/DOWN to increase or decrease the value. 72 | 73 | 74 | ); 75 | }; 76 | -------------------------------------------------------------------------------- /src/SubmitButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Text, Box, useFocus, useInput } from 'ink'; 3 | 4 | export const SubmitButton: React.FC<{ 5 | canSubmit: boolean; 6 | onSubmit: () => void; 7 | }> = props => { 8 | const { isFocused } = useFocus({ isActive: props.canSubmit }); 9 | useInput((input, key) => { 10 | if (key.return && isFocused && props.canSubmit) { 11 | props.onSubmit(); 12 | } 13 | }); 14 | 15 | return ( 16 | 17 | 18 | 19 | {!props.canSubmit 20 | ? 'There are still required inputs you have not competed yet.' 21 | : isFocused 22 | ? 'Press Enter to submit form' 23 | : 'Use the arrow keys to navigate to the submit button.'} 24 | 25 | 26 | 27 | 28 | {props.canSubmit ? 'Submit form' : 'Cannot submit form yet'} 29 | 30 | 31 | 32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /src/canSubmit.ts: -------------------------------------------------------------------------------- 1 | import { FormStructure } from './types.js'; 2 | 3 | export const canSubmit = (form: FormStructure, value: object) => { 4 | return form.sections 5 | .map(section => section.fields) 6 | .reduce((fields1, fields2) => [...fields1, ...fields2], []) 7 | .map(field => !field.required || (value[field.name] !== undefined && value[field.name] !== '')) 8 | .reduce((field1, field2) => field1 && field2, true); 9 | }; 10 | -------------------------------------------------------------------------------- /src/demo/custommanager.tsx: -------------------------------------------------------------------------------- 1 | import { Box, render, Text } from 'ink'; 2 | import { Form } from '../Form.js'; 3 | import React from 'react'; 4 | import { AbstractFormField, FormFieldManager } from '../types.js'; 5 | import TextInput from 'ink-text-input'; 6 | 7 | type CustomField = AbstractFormField<'custom', string> & { length: number }; 8 | 9 | render( 10 | console.log(`Submitted: `, value)} 12 | customManagers={[{ 13 | type: 'custom', 14 | renderValue: ({ value, field }) => <>{value}, 15 | renderField: props => ( 16 | { 19 | props.onChange(value); 20 | 21 | if (value.length > props.field.length) { 22 | props.onError(`Value is too long, should be less or equal than ${props.field.length}`); 23 | } else { 24 | props.onClearError(); 25 | } 26 | }} 27 | placeholder={props.field.placeholder} 28 | /> 29 | ) 30 | } as any]} 31 | form={{ 32 | title: "Custom Form Field Manager", 33 | sections: [ 34 | { 35 | title: "Main", 36 | description: 'Demonstration of how custom field implementations can be used.', 37 | fields: [ 38 | { 39 | type: 'custom', 40 | name: 'Custom field', 41 | length: 10, 42 | description: 'I may not be longer than 10 characters' 43 | } as CustomField as any, 44 | ] 45 | }, 46 | ] 47 | }} 48 | /> 49 | ); 50 | -------------------------------------------------------------------------------- /src/demo/imperative.ts: -------------------------------------------------------------------------------- 1 | import { openForm } from '../imperativeInterface.js'; 2 | import { FormProps } from '../types.js'; 3 | 4 | const form: FormProps = { 5 | form: { 6 | title: "Form title", 7 | sections: [ 8 | { 9 | title: "Text fields", 10 | fields: [ 11 | {type: 'string', name: 'field1', label: 'Input with initial value', initialValue: 'Initial value'}, 12 | {type: 'string', name: 'field2', label: 'Masked input', mask: '*'}, 13 | { 14 | type: 'string', 15 | name: 'field3', 16 | label: 'Input with placeholder, description and required flag', 17 | placeholder: 'Placeholder', 18 | required: true, 19 | description: 'Hello I am a description' 20 | }, 21 | {type: 'string', name: 'field4-nolabel'}, 22 | { 23 | type: 'string', 24 | name: 'field5', 25 | label: 'Regex, must be an url', 26 | regex: /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/ 27 | }, 28 | ] 29 | }, 30 | ] 31 | } 32 | }; 33 | 34 | (async () => { 35 | const result = await openForm(form); 36 | console.log(`Finished with value`, result); 37 | })(); 38 | 39 | -------------------------------------------------------------------------------- /src/demo/overview.tsx: -------------------------------------------------------------------------------- 1 | import { render } from 'ink'; 2 | import { Form } from '../Form.js'; 3 | import React from 'react'; 4 | 5 | const options = [ 6 | {label: 'Millenium Falcon', value: 'falcon'}, 7 | {label: 'TIE Advanced X1', value: 'tieadv'}, 8 | {label: 'X-Wing', value: 'xwing'}, 9 | {label: 'Raizorcrest', value: 'mando'}, 10 | ]; 11 | 12 | render( 13 | console.log(`Submitted: `, value)} 15 | form={{ 16 | title: "Form title", 17 | sections: [ 18 | { 19 | title: "Text fields", 20 | fields: [ 21 | { type: 'string', name: 'field1', label: 'Input with initial value', initialValue: 'Initial value' }, 22 | { type: 'string', name: 'field2', label: 'Masked input', mask: '*' }, 23 | { type: 'string', name: 'field3', label: 'Input with placeholder, description and required flag', placeholder: 'Placeholder', required: true, description: 'Hello I am a description' }, 24 | { type: 'string', name: 'field4-nolabel' }, 25 | { type: 'string', name: 'field5', label: 'Regex, must be an url', regex: /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/ }, 26 | ] 27 | }, 28 | { 29 | title: "Numerical fields", 30 | fields: [ 31 | { type: 'integer', name: 'field10', label: 'Integer' }, 32 | { type: 'integer', name: 'field11', label: 'Integer between -5 and 8, stepsize 2', min: -5, max: 8, step: 2 }, 33 | { type: 'float', name: 'field12', label: 'Float' }, 34 | { type: 'float', name: 'field13', label: 'Float between 0 and 5, stepsize 0.1', min: 0, max: 5, step: .1 }, 35 | ] 36 | }, 37 | { 38 | title: "Selection fields", 39 | fields: [ 40 | { type: 'select', name: 'field20', label: 'Select', options }, 41 | ] 42 | }, 43 | { 44 | title: 'Help Section', 45 | description: [ 46 | 'You can use a section without any fields and just a description attribute for additional documentation sections.', 47 | 'This section for example can help as a help page.', 48 | 'You could also add a "About", "Readme" or different pages.', 49 | ], 50 | fields: [], 51 | } 52 | ] 53 | }} 54 | /> 55 | ); 56 | -------------------------------------------------------------------------------- /src/demo/packagejson.tsx: -------------------------------------------------------------------------------- 1 | import { render } from 'ink'; 2 | import { Form } from '../Form.js'; 3 | import React from 'react'; 4 | 5 | const licenses = [ 6 | 'MIT', 'CC-BY-SA-4.0', 'CC-BY-ND-4.0', 'CC-BY-NC-SA-4.0', 'CC-BY-NC-ND-4.0', 'CC-BY-NC-4.0', 'CC-BY-4.0', 'BSD-4-Clause-UC', 'Apache-2.0', 'W3C-20150513', 7 | ].map(value => ({ value })); 8 | 9 | render( 10 | console.log(`Submitted: `, value)} 12 | form={{ 13 | title: "Edit your package.json file", 14 | sections: [ 15 | { 16 | title: "Basics", 17 | description: 'General attributes of your package.json file.', 18 | fields: [ 19 | { 20 | type: 'boolean', 21 | name: 'private', 22 | label: 'Is private?', 23 | required: true, 24 | initialValue: false, 25 | description: 'If you set "private": true in your package.json, then npm will refuse to publish it.\n\nThis is a way to prevent accidental publication of private repositories. If you would like to ensure that a given package is only ever published to a specific registry (for example, an internal registry), then use the publishConfig dictionary described below to override the registry config param at publish-time.' 26 | }, 27 | { 28 | type: 'string', 29 | name: 'name', 30 | label: 'Package name', 31 | initialValue: '@scope/name', 32 | required: true, 33 | description: 'If you plan to publish your package, the most important things in your package.json are the name and version fields as they will be required. The name and version together form an identifier that is assumed to be completely unique. Changes to the package should come along with changes to the version. If you don\'t plan to publish your package, the name and version fields are optional.' 34 | }, 35 | { 36 | type: 'string', 37 | name: 'version', 38 | label: 'Version', 39 | initialValue: '1.0.0', 40 | required: true, 41 | regex: /^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$/, 42 | description: 'If you plan to publish your package, the most important things in your package.json are the name and version fields as they will be required. The name and version together form an identifier that is assumed to be completely unique. Changes to the package should come along with changes to the version. If you don\'t plan to publish your package, the name and version fields are optional.' 43 | }, 44 | { 45 | type: 'string', 46 | name: 'description', 47 | label: 'Description', 48 | description: 'Put a description in it. It\'s a string. This helps people discover your package, as it\'s listed in npm search.' 49 | }, 50 | { 51 | type: 'string', 52 | name: 'author', 53 | label: 'Author' 54 | }, 55 | { 56 | type: 'select', 57 | name: 'license', 58 | label: 'License', 59 | description: 'You should specify a license for your package so that people know how they are permitted to use it, and any restrictions you\'re placing on it.\n\nIf you\'re using a common license such as BSD-2-Clause or MIT, add a current SPDX license identifier for the license you\'re using, like this:', 60 | options: licenses 61 | }, 62 | { 63 | type: 'string', 64 | name: 'keywords', 65 | label: 'Keywords', 66 | description: 'Put keywords in it, seperated by spaces. This helps people discover your package as it\'s listed in npm search.' 67 | }, 68 | ] 69 | }, 70 | { 71 | title: "Links", 72 | description: 'URLs to external locations that are relevant for your poject.', 73 | fields: [ 74 | { 75 | type: 'string', 76 | name: 'repository', 77 | label: 'Repository', 78 | description: 'Specify the place where your code lives. This is helpful for people who want to contribute. If the git repo is on GitHub, then the npm docs command will be able to find you.' 79 | }, 80 | { 81 | type: 'string', 82 | name: 'homepage', 83 | label: 'Homepage', 84 | regex: /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/, 85 | description: 'The url to the project homepage.' 86 | }, 87 | { 88 | type: 'string', 89 | name: 'bugs', 90 | label: 'Bugtracker', 91 | regex: /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/, 92 | description: 'The url to your project\'s issue tracker and / or the email address to which issues should be reported. These are helpful for people who encounter issues with your package.' 93 | }, 94 | { 95 | type: 'string', 96 | name: 'funding', 97 | label: 'Funding', 98 | regex: /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/, 99 | description: 'You can specify an object containing an URL that provides up-to-date information about ways to help fund development of your package.' 100 | }, 101 | ] 102 | }, 103 | { 104 | title: "Files", 105 | description: 'Files within your project structure that should be associated with your node project.', 106 | fields: [ 107 | { 108 | type: 'string', 109 | name: 'files', 110 | label: 'Files', 111 | description: 'The optional files field is an array of file patterns that describes the entries to be included when your package is installed as a dependency. File patterns follow a similar syntax to .gitignore, but reversed: including a file, directory, or glob pattern (*, **/*, and such) will make it so that file is included in the tarball when it\'s packed. Omitting the field will make it default to ["*"], which means it will include all files.' 112 | }, 113 | { 114 | type: 'string', 115 | name: 'bin', 116 | label: 'bin', 117 | description: 'A lot of packages have one or more executable files that they\'d like to install into the PATH. npm makes this pretty easy (in fact, it uses this feature to install the "npm" executable.)\n\nTo use this, supply a bin field in your package.json which is a map of command name to local file name. On install, npm will symlink that file into prefix/bin for global installs, or ./node_modules/.bin/ for local installs.' 118 | }, 119 | { 120 | type: 'string', 121 | name: 'man', 122 | label: 'man', 123 | description: 'Specify either a single file or an array of filenames to put in place for the man program to find.' 124 | }, 125 | { 126 | type: 'string', 127 | name: 'main', 128 | label: 'main', 129 | description: 'The main field is a module ID that is the primary entry point to your program. That is, if your package is named foo, and a user installs it, and then does require("foo"), then your main module\'s exports object will be returned.\n\nThis should be a module relative to the root of your package folder.\n\nFor most modules, it makes the most sense to have a main script and often not much else.' 130 | }, 131 | ] 132 | }, 133 | { 134 | title: 'Scripts', 135 | description: 'Command implementation for common npm lifecycle scripts.', 136 | fields: ['npm cache add', 'npm ci', 'npm diff', 'npm install', 'npm pack', 'npm publish', 'npm rebuild', 'npm restart', 'npm start', 'npm stop', 'npm test'].map(scriptName => ({ 137 | type: 'string', 138 | name: `script-${scriptName}`, 139 | label: scriptName, 140 | description: `Command implementation for the ${scriptName} lifecycle script.` 141 | })) 142 | } 143 | ] 144 | }} 145 | /> 146 | ); 147 | -------------------------------------------------------------------------------- /src/imperativeInterface.tsx: -------------------------------------------------------------------------------- 1 | import { FormProps } from './types.js'; 2 | import { render } from 'ink'; 3 | import { Form } from './Form.js'; 4 | import React from 'react'; 5 | 6 | export const openForm = async (options: Omit): Promise<{ [key: string]: any }> => { 7 | return new Promise(res => { 8 | const { clear, unmount } = render( 9 | { 12 | clear(); 13 | unmount(); 14 | res(value); 15 | }} 16 | /> 17 | ); 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types.js'; 2 | export * from './Form.js'; 3 | export * from './imperativeInterface.js'; 4 | -------------------------------------------------------------------------------- /src/managers/BooleanFormFieldManager.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | FormFieldBoolean, 3 | FormFieldManager, 4 | FormFieldValueRendererProps, 5 | SpecificFormFieldRendererProps, 6 | TypeOfField, 7 | } from '../types.js'; 8 | import React from 'react'; 9 | import { Box, Text, useInput } from 'ink'; 10 | 11 | export class BooleanFormFieldManager implements FormFieldManager { 12 | public type: TypeOfField = 'boolean'; 13 | 14 | public renderField: React.FC> = props => { 15 | useInput((input, key) => { 16 | if (input === ' ') { 17 | props.onChange(!props.value); 18 | } 19 | }); 20 | 21 | return ( 22 | 23 | 24 | 25 | {props.value === undefined ? '[Not set]' : props.value ? '[True]' : '[False]'} 26 | 27 | 28 | 29 | Press Space to toggle value 30 | 31 | 32 | ); 33 | }; 34 | 35 | public renderValue: React.FC> = props => ( 36 | {props.value === undefined ? '[Not set]' : props.value ? '[True]' : '[False]'} 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/managers/FloatFormFieldManager.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | FormFieldFloat, 3 | FormFieldManager, 4 | FormFieldValueRendererProps, 5 | SpecificFormFieldRendererProps, 6 | TypeOfField, 7 | } from '../types.js'; 8 | import React from 'react'; 9 | import { NumberFieldRenderer } from '../NumberFieldRenderer.js'; 10 | 11 | export class FloatFormFieldManager implements FormFieldManager { 12 | public type: TypeOfField = 'float'; 13 | 14 | public renderField: React.FC> = props => ( 15 | 16 | ); 17 | 18 | public renderValue: React.FC> = props => <>{props.value}; 19 | } 20 | -------------------------------------------------------------------------------- /src/managers/IntegerFormFieldManager.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | FormFieldInteger, 3 | FormFieldManager, 4 | FormFieldValueRendererProps, 5 | SpecificFormFieldRendererProps, 6 | TypeOfField, 7 | } from '../types.js'; 8 | import React from 'react'; 9 | import { NumberFieldRenderer } from '../NumberFieldRenderer.js'; 10 | 11 | export class IntegerFormFieldManager implements FormFieldManager { 12 | public type: TypeOfField = 'integer'; 13 | 14 | public renderField: React.FC> = props => ( 15 | 16 | ); 17 | 18 | public renderValue: React.FC> = props => <>{props.value}; 19 | } 20 | -------------------------------------------------------------------------------- /src/managers/SelectFormFieldManager.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | FormFieldManager, 3 | FormFieldSelect, 4 | FormFieldValueRendererProps, 5 | SpecificFormFieldRendererProps, 6 | TypeOfField, 7 | } from '../types.js'; 8 | import React from 'react'; 9 | import { Box } from 'ink'; 10 | import SelectInput from 'ink-select-input'; 11 | 12 | export class SelectFormFieldManager implements FormFieldManager { 13 | public type: TypeOfField = 'select'; 14 | 15 | public renderField: React.FC> = props => ( 16 | 17 | ({ value: option.value, label: option.label ?? option.value }))} 19 | onHighlight={option => props.onChange(option.value)} 20 | initialIndex={props.field.options.findIndex(option => option.value === props.value) ?? 0} 21 | /> 22 | 23 | ); 24 | 25 | public renderValue: React.FC> = props => ( 26 | <>{props.field.options.find(option => option.value === props.value)?.label ?? props.value ?? 'No value'} 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /src/managers/StringFormFieldManager.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | FormFieldManager, 3 | FormFieldString, 4 | FormFieldValueRendererProps, 5 | SpecificFormFieldRendererProps, 6 | TypeOfField, 7 | } from '../types.js'; 8 | import React from 'react'; 9 | import { Box, Text, Transform } from 'ink'; 10 | import TextInput from 'ink-text-input'; 11 | 12 | export class StringFormFieldManager implements FormFieldManager { 13 | public type: TypeOfField = 'string'; 14 | 15 | public renderField: React.FC> = props => ( 16 | 17 | { 20 | props.onChange(value); 21 | 22 | if (props.field.regex && !props.field.regex.test(value)) { 23 | props.onError(`Value does not conform to regular expression: ${props.field.regex}`); 24 | } else { 25 | props.onClearError(); 26 | } 27 | }} 28 | placeholder={props.field.placeholder} 29 | onSubmit={() => props.onSetEditingField(undefined)} 30 | mask={props.field.mask} 31 | /> 32 | 33 | ); 34 | 35 | public renderValue: React.FC> = props => ( 36 | 40 | text 41 | .split('') 42 | .map(char => '*') 43 | .join('') 44 | : text => text 45 | } 46 | > 47 | {props.value} 48 | 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/managers/managers.ts: -------------------------------------------------------------------------------- 1 | import { FloatFormFieldManager } from './FloatFormFieldManager.js'; 2 | import { IntegerFormFieldManager } from './IntegerFormFieldManager.js'; 3 | import { SelectFormFieldManager } from './SelectFormFieldManager.js'; 4 | import { FormField, FormFieldManager, TypeOfField } from '../types.js'; 5 | import { StringFormFieldManager } from './StringFormFieldManager.js'; 6 | import { BooleanFormFieldManager } from './BooleanFormFieldManager.js'; 7 | 8 | export const managers: FormFieldManager[] = [ 9 | new FloatFormFieldManager(), 10 | new IntegerFormFieldManager(), 11 | new SelectFormFieldManager(), 12 | new StringFormFieldManager(), 13 | new BooleanFormFieldManager(), 14 | ]; 15 | 16 | export const getManager = ( 17 | formFieldType: TypeOfField, 18 | customManagers: FormFieldManager[] = [] 19 | ) => { 20 | return [...managers, ...customManagers].find(manager => manager.type === formFieldType); 21 | }; 22 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | /** 4 | * A description for either a field or a section. If undefined or false, it will not be shown. 5 | * If its a JSX.Element, it will be rendered as description. If its a string, the string 6 | * will be rendered. If its an array of strings, they will be rendered as distinctive paragraphs. 7 | */ 8 | export type Description = string | string[] | JSX.Element | undefined | false; 9 | 10 | /** 11 | * The input structure for creating a new form, either by directly rendering it as component in 12 | * Ink, or by invoking ``openForm(form)`` with it. You have to supply a ``form`` attribute to 13 | * define the structure of the form. You should also supply a ``onSubmit`` attribute to receive 14 | * the results when the user submits the form. 15 | * 16 | * The form is uncontrolled by default, you can specify an initial value with ``initialValue``. You 17 | * can also switch to controlled mode by explicitly setting a ``value`` and reacting to ``onChange`` 18 | * events. 19 | */ 20 | export interface FormProps { 21 | /** Structure of the form, i.e. which fields are contained in which sections. */ 22 | form: FormStructure; 23 | initialValue?: object; 24 | 25 | /** Current value of the form. Omit to leave the component in uncontrolled mode. */ 26 | value?: object; 27 | onChange?: (value: object) => void; 28 | 29 | /** 30 | * ``onSubmit`` is triggered when the user has completed all required fields and triggers the 31 | * submit button at the end of the page. 32 | * 33 | * @param value the final value of the form. 34 | * */ 35 | onSubmit?: (value: object) => void; 36 | 37 | /** 38 | * You can use custom field implementations, by specifying their ``type`` attribute to a custom 39 | * value and supplying a FormFieldManager here that can handle this type. 40 | */ 41 | customManagers?: FormFieldManager>[]; 42 | } 43 | 44 | /** 45 | * Top-level structure of the form. A form is composed of several sections, which are 46 | * displayed as distinct tabs, each containing several fields. 47 | */ 48 | export interface FormStructure { 49 | /** The title of the form is shown at the top throughout the application. */ 50 | title?: string; 51 | /** A form contains several sections, each displayed as a tab. */ 52 | sections: FormSection[]; 53 | } 54 | 55 | /** 56 | * A form is composed of several sections of which only one can be shown at once. It is 57 | * composed of several form fields. The title is shown as tab-text for the section. 58 | * A description can be supplied which will be shown at the top of the form. 59 | * 60 | * Note that all form fields are stored in a global value object, regardless of section structure. 61 | */ 62 | export interface FormSection { 63 | /** Title of the section, will be shown as its tab name. */ 64 | title: string; 65 | /** List of form fields which are visible when this section is open. */ 66 | fields: FormField[]; 67 | /** Optional text that describes this section. */ 68 | description?: Description; 69 | } 70 | 71 | /** 72 | * A form field describes a type of input, i.e. text input, number input etc. 73 | * 74 | * Included are: 75 | * - FormFieldString 76 | * - FormFieldInteger 77 | * - FormFieldFloat 78 | * - FormFieldSelect 79 | * - FormFieldBoolean 80 | * 81 | * You can add your own form field by extending ``AbstractFormField`` and implementing 82 | * an associated ``FormFieldManager``. 83 | */ 84 | export type FormField = 85 | | FormFieldString 86 | | FormFieldInteger 87 | | FormFieldFloat 88 | | FormFieldSelect 89 | | FormFieldBoolean 90 | | AbstractFormField; 91 | 92 | export type ValueOfField = T extends AbstractFormField ? V : never; 93 | export type TypeOfField = T extends AbstractFormField ? V : never; 94 | 95 | export type AbstractFormField = { 96 | /** 97 | * The type uniquely identifies which kind of form field is used, e.g. 'string', 'integer'. This tells 98 | * the library which form field manager should be used to handle this form field. 99 | */ 100 | type: T; 101 | 102 | /** 103 | * The name uniquely identifies the input field and is used to store the value in the output 104 | * structure, i.e. if ``field.name === 'myFieldName'``, then the value chosen by the user 105 | * is available in the output stucture in ``output['myFieldName']``. Note that the section 106 | * structure is irrelevant for the output structure, just the name uniquely identifies the 107 | * field. 108 | */ 109 | name: string; 110 | 111 | /** 112 | * A quick description of the field. If omitted, the name will be used as label. 113 | */ 114 | label?: string; 115 | 116 | /** An optional verbose description which will only be shown when the field is expanded. */ 117 | description?: Description; 118 | 119 | /** If this is set to true, the form cannot be submitted if this fields value is empty or undefined. */ 120 | required?: boolean; 121 | initialValue?: V; 122 | onChange?: (value: V, name: string) => void; 123 | }; 124 | 125 | export type FormFieldBoolean = AbstractFormField<'boolean', boolean> & {}; 126 | 127 | export type FormFieldString = AbstractFormField<'string', string> & { 128 | /** Set to e.g. ``*`` to use as password field. */ 129 | mask?: string; 130 | 131 | /** If supplied, the user cannot use a value which does not conform this regular expression. */ 132 | regex?: RegExp; 133 | placeholder?: string; 134 | }; 135 | 136 | export type FormFieldInteger = AbstractFormField<'integer', number> & { 137 | min?: number; 138 | max?: number; 139 | /** The user can use the arrow keys to increase or decrease the value by that step amount. */ 140 | step?: number; 141 | placeholder?: string; 142 | }; 143 | 144 | export type FormFieldFloat = AbstractFormField<'float', number> & { 145 | min?: number; 146 | max?: number; 147 | /** The user can use the arrow keys to increase or decrease the value by that step amount. */ 148 | step?: number; 149 | placeholder?: string; 150 | }; 151 | 152 | export type FormFieldSelect = AbstractFormField<'select', string> & { 153 | options: Array<{ label?: string; value: string }>; 154 | }; 155 | 156 | export interface FormFieldValueRendererProps { 157 | value?: ValueOfField; 158 | field: T; 159 | } 160 | 161 | /** 162 | * A FormFieldManager is responsible for handling a input kind, i.e. a ``FormField``, by specifying 163 | * how its input should be rendered. Implement a custom ``FormFieldManager`` and supply it to the 164 | * form to add custom form fields. 165 | */ 166 | export interface FormFieldManager { 167 | /** This value must match the ``FormField.type`` value you use for your custom form fields. */ 168 | type: TypeOfField; 169 | needCtrlToReturnSave?: boolean; 170 | /** Render method for rendering the input component if the field is expanded. */ 171 | renderField: React.FC>; 172 | /** Render method for rendering the value if the field is collapsed. */ 173 | renderValue: React.FC>; 174 | } 175 | 176 | export type FormFieldRendererProps = { 177 | field: T; 178 | form: FormStructure; 179 | value?: ValueOfField; 180 | onChange: (value: ValueOfField) => void; 181 | onSetEditingField: (field?: string) => void; 182 | editingField?: string; 183 | customManagers?: FormFieldManager[]; 184 | }; 185 | 186 | export type SpecificFormFieldRendererProps = FormFieldRendererProps & { 187 | onError: (error: string) => void; 188 | onClearError: () => void; 189 | error?: string; 190 | onSave: (newValue?: ValueOfField) => void; 191 | onCancel: () => void; 192 | }; 193 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["ESNext"], 5 | "esModuleInterop": true, 6 | "jsx": "react", 7 | "declaration": true, 8 | "module": "Node16", 9 | "outDir": "lib", 10 | "strictNullChecks": true, 11 | "moduleResolution": "Node16", 12 | "allowJs": false, 13 | "rootDir": "src" 14 | }, 15 | "exclude": ["node_modules", "**/*.spec.ts", "**/*.spec.tsx", "lib", "docs"] 16 | } 17 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 8 6 | cacheKey: 10 7 | 8 | "@alcalzone/ansi-tokenize@npm:^0.1.3": 9 | version: 0.1.3 10 | resolution: "@alcalzone/ansi-tokenize@npm:0.1.3" 11 | dependencies: 12 | ansi-styles: "npm:^6.2.1" 13 | is-fullwidth-code-point: "npm:^4.0.0" 14 | checksum: 3fff28b9cd039321ab8d78f1cda26a932c801ad58a86b06d1bafa7599a8d3076c67c92bee1cbdccaa837a2b088604c976f75911da2bc03d8f8d03a042c7828a0 15 | languageName: node 16 | linkType: hard 17 | 18 | "@cspotcode/source-map-support@npm:^0.8.0": 19 | version: 0.8.1 20 | resolution: "@cspotcode/source-map-support@npm:0.8.1" 21 | dependencies: 22 | "@jridgewell/trace-mapping": "npm:0.3.9" 23 | checksum: b6e38a1712fab242c86a241c229cf562195aad985d0564bd352ac404be583029e89e93028ffd2c251d2c407ecac5fb0cbdca94a2d5c10f29ac806ede0508b3ff 24 | languageName: node 25 | linkType: hard 26 | 27 | "@jridgewell/resolve-uri@npm:^3.0.3": 28 | version: 3.1.1 29 | resolution: "@jridgewell/resolve-uri@npm:3.1.1" 30 | checksum: 64d59df8ae1a4e74315eb1b61e012f1c7bc8aac47a3a1e683f6fe7008eab07bc512a742b7aa7c0405685d1421206de58c9c2e6adbfe23832f8bd69408ffc183e 31 | languageName: node 32 | linkType: hard 33 | 34 | "@jridgewell/sourcemap-codec@npm:^1.4.10": 35 | version: 1.4.15 36 | resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" 37 | checksum: 89960ac087781b961ad918978975bcdf2051cd1741880469783c42de64239703eab9db5230d776d8e6a09d73bb5e4cb964e07d93ee6e2e7aea5a7d726e865c09 38 | languageName: node 39 | linkType: hard 40 | 41 | "@jridgewell/trace-mapping@npm:0.3.9": 42 | version: 0.3.9 43 | resolution: "@jridgewell/trace-mapping@npm:0.3.9" 44 | dependencies: 45 | "@jridgewell/resolve-uri": "npm:^3.0.3" 46 | "@jridgewell/sourcemap-codec": "npm:^1.4.10" 47 | checksum: 83deafb8e7a5ca98993c2c6eeaa93c270f6f647a4c0dc00deb38c9cf9b2d3b7bf15e8839540155247ef034a052c0ec4466f980bf0c9e2ab63b97d16c0cedd3ff 48 | languageName: node 49 | linkType: hard 50 | 51 | "@kwsites/file-exists@npm:^1.1.1": 52 | version: 1.1.1 53 | resolution: "@kwsites/file-exists@npm:1.1.1" 54 | dependencies: 55 | debug: "npm:^4.1.1" 56 | checksum: 4ff945de7293285133aeae759caddc71e73c4a44a12fac710fdd4f574cce2671a3f89d8165fdb03d383cfc97f3f96f677d8de3c95133da3d0e12a123a23109fe 57 | languageName: node 58 | linkType: hard 59 | 60 | "@kwsites/promise-deferred@npm:^1.1.1": 61 | version: 1.1.1 62 | resolution: "@kwsites/promise-deferred@npm:1.1.1" 63 | checksum: 07455477a0123d9a38afb503739eeff2c5424afa8d3dbdcc7f9502f13604488a4b1d9742fc7288832a52a6422cf1e1c0a1d51f69a39052f14d27c9a0420b6629 64 | languageName: node 65 | linkType: hard 66 | 67 | "@octokit/auth-token@npm:^3.0.0": 68 | version: 3.0.4 69 | resolution: "@octokit/auth-token@npm:3.0.4" 70 | checksum: 8e21e567e38ba307fa30497ad77801135e25c328ce8b363c1622a4afb408a7d3315d54082527b38ecd5b3a5449680d89cfca9cb10c516cacf3dfa01e4c8b7195 71 | languageName: node 72 | linkType: hard 73 | 74 | "@octokit/core@npm:^4.2.1": 75 | version: 4.2.4 76 | resolution: "@octokit/core@npm:4.2.4" 77 | dependencies: 78 | "@octokit/auth-token": "npm:^3.0.0" 79 | "@octokit/graphql": "npm:^5.0.0" 80 | "@octokit/request": "npm:^6.0.0" 81 | "@octokit/request-error": "npm:^3.0.0" 82 | "@octokit/types": "npm:^9.0.0" 83 | before-after-hook: "npm:^2.2.0" 84 | universal-user-agent: "npm:^6.0.0" 85 | checksum: 53ba8f990ce2c0ea4583d8c142377770c3ac8fb9221b563d82dbca9d642f19be49607b9e9b472767075e4afa16c2203339680d75f3ebf5ad853af2646e8604ca 86 | languageName: node 87 | linkType: hard 88 | 89 | "@octokit/endpoint@npm:^7.0.0": 90 | version: 7.0.6 91 | resolution: "@octokit/endpoint@npm:7.0.6" 92 | dependencies: 93 | "@octokit/types": "npm:^9.0.0" 94 | is-plain-object: "npm:^5.0.0" 95 | universal-user-agent: "npm:^6.0.0" 96 | checksum: e8b9cc09aa8306d63cb0e5b65ac5d29fc421522c92810a9d70bbfef997bc8750fc339f1f4f60e1604c22db77457ea493c51849b0d61cbfcb8655b0c4f2640e4b 97 | languageName: node 98 | linkType: hard 99 | 100 | "@octokit/graphql@npm:^5.0.0": 101 | version: 5.0.6 102 | resolution: "@octokit/graphql@npm:5.0.6" 103 | dependencies: 104 | "@octokit/request": "npm:^6.0.0" 105 | "@octokit/types": "npm:^9.0.0" 106 | universal-user-agent: "npm:^6.0.0" 107 | checksum: 6014690d184d7b2bfb56ab9be5ddbe4f5c77aa6031d71ec2caf5f56cbd32f4a5b0601049cef7dce1ca8010b89a9fc8bb07ce7833e6213c5bc77b7a564b1f40b9 108 | languageName: node 109 | linkType: hard 110 | 111 | "@octokit/openapi-types@npm:^18.0.0": 112 | version: 18.1.1 113 | resolution: "@octokit/openapi-types@npm:18.1.1" 114 | checksum: bd2920a238f74c6ccc1e2ee916bd3e17adeeef3bbb1726f821b8722dceaeff5ea2786b3170cc25dd51775cb9179d3cdf448a3526e70b8a1fc21cdd8aa52e5d4c 115 | languageName: node 116 | linkType: hard 117 | 118 | "@octokit/plugin-paginate-rest@npm:^6.1.2": 119 | version: 6.1.2 120 | resolution: "@octokit/plugin-paginate-rest@npm:6.1.2" 121 | dependencies: 122 | "@octokit/tsconfig": "npm:^1.0.2" 123 | "@octokit/types": "npm:^9.2.3" 124 | peerDependencies: 125 | "@octokit/core": ">=4" 126 | checksum: 6d5b97fb44a3ed8ff25196b56ebe7bdac64f4023c165792f77938c77876934c01b46e79b83712e26cd3f2f9e36e0735bd3c292a37e8060a2b259f3a6456116dc 127 | languageName: node 128 | linkType: hard 129 | 130 | "@octokit/plugin-request-log@npm:^1.0.4": 131 | version: 1.0.4 132 | resolution: "@octokit/plugin-request-log@npm:1.0.4" 133 | peerDependencies: 134 | "@octokit/core": ">=3" 135 | checksum: 2086db00056aee0f8ebd79797b5b57149ae1014e757ea08985b71eec8c3d85dbb54533f4fd34b6b9ecaa760904ae6a7536be27d71e50a3782ab47809094bfc0c 136 | languageName: node 137 | linkType: hard 138 | 139 | "@octokit/plugin-rest-endpoint-methods@npm:^7.1.2": 140 | version: 7.2.3 141 | resolution: "@octokit/plugin-rest-endpoint-methods@npm:7.2.3" 142 | dependencies: 143 | "@octokit/types": "npm:^10.0.0" 144 | peerDependencies: 145 | "@octokit/core": ">=3" 146 | checksum: 59fb4e786ab85a5f3ad701e1b193dd3113833cfd1f2657cb06864e45b80a53a1f9ba6c3c66a855c4bf2593c539299fdfe51db639e3a87dc16ffa7602fe9bb999 147 | languageName: node 148 | linkType: hard 149 | 150 | "@octokit/request-error@npm:^3.0.0": 151 | version: 3.0.3 152 | resolution: "@octokit/request-error@npm:3.0.3" 153 | dependencies: 154 | "@octokit/types": "npm:^9.0.0" 155 | deprecation: "npm:^2.0.0" 156 | once: "npm:^1.4.0" 157 | checksum: 5db0b514732686b627e6ed9ef1ccdbc10501f1b271a9b31f784783f01beee70083d7edcfeb35fbd7e569fa31fdd6762b1ff6b46101700d2d97e7e48e749520d0 158 | languageName: node 159 | linkType: hard 160 | 161 | "@octokit/request@npm:^6.0.0": 162 | version: 6.2.8 163 | resolution: "@octokit/request@npm:6.2.8" 164 | dependencies: 165 | "@octokit/endpoint": "npm:^7.0.0" 166 | "@octokit/request-error": "npm:^3.0.0" 167 | "@octokit/types": "npm:^9.0.0" 168 | is-plain-object: "npm:^5.0.0" 169 | node-fetch: "npm:^2.6.7" 170 | universal-user-agent: "npm:^6.0.0" 171 | checksum: 47188fa08d28e5e9e6a22f84058fc13f108cdcb68aea97686da4718d32d3ddda8fde8a5c9f189057e3d466560b67c2305a2e343d1eed9517b47a13f68cb329e7 172 | languageName: node 173 | linkType: hard 174 | 175 | "@octokit/rest@npm:^19.0.7": 176 | version: 19.0.13 177 | resolution: "@octokit/rest@npm:19.0.13" 178 | dependencies: 179 | "@octokit/core": "npm:^4.2.1" 180 | "@octokit/plugin-paginate-rest": "npm:^6.1.2" 181 | "@octokit/plugin-request-log": "npm:^1.0.4" 182 | "@octokit/plugin-rest-endpoint-methods": "npm:^7.1.2" 183 | checksum: 7fbee09a2f832be6802a026713aa93cbf82dcfc8103d68c585b23214caf0accfced6efe2c49169158d39875d5c5ad3994b83b02e26537b75687ac16d0572c212 184 | languageName: node 185 | linkType: hard 186 | 187 | "@octokit/tsconfig@npm:^1.0.2": 188 | version: 1.0.2 189 | resolution: "@octokit/tsconfig@npm:1.0.2" 190 | checksum: 74d56f3e9f326a8dd63700e9a51a7c75487180629c7a68bbafee97c612fbf57af8347369bfa6610b9268a3e8b833c19c1e4beb03f26db9a9dce31f6f7a19b5b1 191 | languageName: node 192 | linkType: hard 193 | 194 | "@octokit/types@npm:^10.0.0": 195 | version: 10.0.0 196 | resolution: "@octokit/types@npm:10.0.0" 197 | dependencies: 198 | "@octokit/openapi-types": "npm:^18.0.0" 199 | checksum: 6345e605d30c99639a0207cfc7bea5bf29d9007e93cdcd78be3f8218830a462a0f0fbb976f5c2d9ebe70ee2aa33d1b72243cdb955478581ee2cead059ac4f030 200 | languageName: node 201 | linkType: hard 202 | 203 | "@octokit/types@npm:^9.0.0, @octokit/types@npm:^9.2.3": 204 | version: 9.3.2 205 | resolution: "@octokit/types@npm:9.3.2" 206 | dependencies: 207 | "@octokit/openapi-types": "npm:^18.0.0" 208 | checksum: 4bcd18850d5397e5835f5686be88ad95e5d7c23e7d53f898b82a8ca5fc1f6a7b53816ef6f9f3b7a06799c0b030d259bf2bd50a258a1656df2dc7f3e533e334f8 209 | languageName: node 210 | linkType: hard 211 | 212 | "@tsconfig/node10@npm:^1.0.7": 213 | version: 1.0.9 214 | resolution: "@tsconfig/node10@npm:1.0.9" 215 | checksum: a33ae4dc2a621c0678ac8ac4bceb8e512ae75dac65417a2ad9b022d9b5411e863c4c198b6ba9ef659e14b9fb609bbec680841a2e84c1172df7a5ffcf076539df 216 | languageName: node 217 | linkType: hard 218 | 219 | "@tsconfig/node12@npm:^1.0.7": 220 | version: 1.0.11 221 | resolution: "@tsconfig/node12@npm:1.0.11" 222 | checksum: 5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a 223 | languageName: node 224 | linkType: hard 225 | 226 | "@tsconfig/node14@npm:^1.0.0": 227 | version: 1.0.3 228 | resolution: "@tsconfig/node14@npm:1.0.3" 229 | checksum: 19275fe80c4c8d0ad0abed6a96dbf00642e88b220b090418609c4376e1cef81bf16237bf170ad1b341452feddb8115d8dd2e5acdfdea1b27422071163dc9ba9d 230 | languageName: node 231 | linkType: hard 232 | 233 | "@tsconfig/node16@npm:^1.0.2": 234 | version: 1.0.4 235 | resolution: "@tsconfig/node16@npm:1.0.4" 236 | checksum: 202319785901f942a6e1e476b872d421baec20cf09f4b266a1854060efbf78cde16a4d256e8bc949d31e6cd9a90f1e8ef8fb06af96a65e98338a2b6b0de0a0ff 237 | languageName: node 238 | linkType: hard 239 | 240 | "@types/node@npm:^14.14.45": 241 | version: 14.18.63 242 | resolution: "@types/node@npm:14.18.63" 243 | checksum: 82a7775898c2ea6db0b610a463512206fb2c7adc1af482c7eb44b99d94375fff51c74f67ae75a63c5532971159f30c866a4d308000624ef02fd9a7175e277019 244 | languageName: node 245 | linkType: hard 246 | 247 | "@types/prop-types@npm:*": 248 | version: 15.7.3 249 | resolution: "@types/prop-types@npm:15.7.3" 250 | checksum: 90064105961cfabb9174e61e5010b4e7a471e21832118ad0258f196f4be19ad7dd0f724cc62b0e90939d0b830d4f49ba54dffde166893fd0d9be1f3b43db6981 251 | languageName: node 252 | linkType: hard 253 | 254 | "@types/react@npm:^18.2.41": 255 | version: 18.2.41 256 | resolution: "@types/react@npm:18.2.41" 257 | dependencies: 258 | "@types/prop-types": "npm:*" 259 | "@types/scheduler": "npm:*" 260 | csstype: "npm:^3.0.2" 261 | checksum: 31a498a56ad3e825ae13799355fe49042c0cdbbe6f40003f39b6b9cf847ba1669393c22ba60e97b1072cf1c002b15432082cdd17e47c948430bdc1f0864829b9 262 | languageName: node 263 | linkType: hard 264 | 265 | "@types/scheduler@npm:*": 266 | version: 0.16.8 267 | resolution: "@types/scheduler@npm:0.16.8" 268 | checksum: 6c091b096daa490093bf30dd7947cd28e5b2cd612ec93448432b33f724b162587fed9309a0acc104d97b69b1d49a0f3fc755a62282054d62975d53d7fd13472d 269 | languageName: node 270 | linkType: hard 271 | 272 | "acorn-walk@npm:^8.1.1": 273 | version: 8.3.0 274 | resolution: "acorn-walk@npm:8.3.0" 275 | checksum: 7673f342db939adc16ac3596c374a56be33e6ef84e01dfb3a0b50cc87cf9b8e46d84c337dcd7d5644f75bf219ad5a36bf33795e9f1af15298e6bceacf46c5f1f 276 | languageName: node 277 | linkType: hard 278 | 279 | "acorn@npm:^8.4.1": 280 | version: 8.11.2 281 | resolution: "acorn@npm:8.11.2" 282 | bin: 283 | acorn: bin/acorn 284 | checksum: ff559b891382ad4cd34cc3c493511d0a7075a51f5f9f02a03440e92be3705679367238338566c5fbd3521ecadd565d29301bc8e16cb48379206bffbff3d72500 285 | languageName: node 286 | linkType: hard 287 | 288 | "ansi-escapes@npm:^6.0.0": 289 | version: 6.2.0 290 | resolution: "ansi-escapes@npm:6.2.0" 291 | dependencies: 292 | type-fest: "npm:^3.0.0" 293 | checksum: 442f91b04650b35bc4815f47c20412d69ddbba5d4bf22f72ec03be352fca2de6819c7e3f4dfd17816ee4e0c6c965fe85e6f1b3f09683996a8d12fd366afd924e 294 | languageName: node 295 | linkType: hard 296 | 297 | "ansi-regex@npm:^6.0.1": 298 | version: 6.0.1 299 | resolution: "ansi-regex@npm:6.0.1" 300 | checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 301 | languageName: node 302 | linkType: hard 303 | 304 | "ansi-sequence-parser@npm:^1.1.0": 305 | version: 1.1.1 306 | resolution: "ansi-sequence-parser@npm:1.1.1" 307 | checksum: 9ce30f257badc2ef62cac8028a7e26c368d22bf26650427192e8ffd102da42e377e3affe90fae58062eecc963b0b055f510dde3b677c7e0c433c67069b5a8ee5 308 | languageName: node 309 | linkType: hard 310 | 311 | "ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1": 312 | version: 6.2.1 313 | resolution: "ansi-styles@npm:6.2.1" 314 | checksum: 70fdf883b704d17a5dfc9cde206e698c16bcd74e7f196ab821511651aee4f9f76c9514bdfa6ca3a27b5e49138b89cb222a28caf3afe4567570139577f991df32 315 | languageName: node 316 | linkType: hard 317 | 318 | "arg@npm:^4.1.0": 319 | version: 4.1.3 320 | resolution: "arg@npm:4.1.3" 321 | checksum: 969b491082f20cad166649fa4d2073ea9e974a4e5ac36247ca23d2e5a8b3cb12d60e9ff70a8acfe26d76566c71fd351ee5e6a9a6595157eb36f92b1fd64e1599 322 | languageName: node 323 | linkType: hard 324 | 325 | "arr-rotate@npm:^1.0.0": 326 | version: 1.0.0 327 | resolution: "arr-rotate@npm:1.0.0" 328 | checksum: f996e94a7b8325c23fe3d7bf95f4f1a5fd1baba34c6bcebb5a8bd0f9b955569293f4cc61f02b0a242380923fca235948e95f6dbf544a6f183207d80e8f2d442d 329 | languageName: node 330 | linkType: hard 331 | 332 | "auto-bind@npm:^5.0.1": 333 | version: 5.0.1 334 | resolution: "auto-bind@npm:5.0.1" 335 | checksum: 44a6d8d040c4382e761922f8fa1b044e18ddefbc855fecee0c76ec6b4e6fc74adda21026bc86e190833e05f52b4b6615372c2a83a734858f8395b1e2a98b253a 336 | languageName: node 337 | linkType: hard 338 | 339 | "balanced-match@npm:^1.0.0": 340 | version: 1.0.0 341 | resolution: "balanced-match@npm:1.0.0" 342 | checksum: 9b67bfe558772f40cf743a3469b48b286aecec2ea9fe80c48d74845e53aab1cef524fafedf123a63019b49ac397760573ef5f173f539423061f7217cbb5fbd40 343 | languageName: node 344 | linkType: hard 345 | 346 | "before-after-hook@npm:^2.2.0": 347 | version: 2.2.3 348 | resolution: "before-after-hook@npm:2.2.3" 349 | checksum: e676f769dbc4abcf4b3317db2fd2badb4a92c0710e0a7da12cf14b59c3482d4febf835ad7de7874499060fd4e13adf0191628e504728b3c5bb4ec7a878c09940 350 | languageName: node 351 | linkType: hard 352 | 353 | "brace-expansion@npm:^2.0.1": 354 | version: 2.0.1 355 | resolution: "brace-expansion@npm:2.0.1" 356 | dependencies: 357 | balanced-match: "npm:^1.0.0" 358 | checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 359 | languageName: node 360 | linkType: hard 361 | 362 | "chalk@npm:^5.2.0, chalk@npm:^5.3.0": 363 | version: 5.3.0 364 | resolution: "chalk@npm:5.3.0" 365 | checksum: 6373caaab21bd64c405bfc4bd9672b145647fc9482657b5ea1d549b3b2765054e9d3d928870cdf764fb4aad67555f5061538ff247b8310f110c5c888d92397ea 366 | languageName: node 367 | linkType: hard 368 | 369 | "ci-info@npm:^3.2.0": 370 | version: 3.9.0 371 | resolution: "ci-info@npm:3.9.0" 372 | checksum: 75bc67902b4d1c7b435497adeb91598f6d52a3389398e44294f6601b20cfef32cf2176f7be0eb961d9e085bb333a8a5cae121cb22f81cf238ae7f58eb80e9397 373 | languageName: node 374 | linkType: hard 375 | 376 | "cli-boxes@npm:^3.0.0": 377 | version: 3.0.0 378 | resolution: "cli-boxes@npm:3.0.0" 379 | checksum: 637d84419d293a9eac40a1c8c96a2859e7d98b24a1a317788e13c8f441be052fc899480c6acab3acc82eaf1bccda6b7542d7cdcf5c9c3cc39227175dc098d5b2 380 | languageName: node 381 | linkType: hard 382 | 383 | "cli-cursor@npm:^4.0.0": 384 | version: 4.0.0 385 | resolution: "cli-cursor@npm:4.0.0" 386 | dependencies: 387 | restore-cursor: "npm:^4.0.0" 388 | checksum: ab3f3ea2076e2176a1da29f9d64f72ec3efad51c0960898b56c8a17671365c26e67b735920530eaf7328d61f8bd41c27f46b9cf6e4e10fe2fa44b5e8c0e392cc 389 | languageName: node 390 | linkType: hard 391 | 392 | "cli-truncate@npm:^3.1.0": 393 | version: 3.1.0 394 | resolution: "cli-truncate@npm:3.1.0" 395 | dependencies: 396 | slice-ansi: "npm:^5.0.0" 397 | string-width: "npm:^5.0.0" 398 | checksum: c3243e41974445691c63f8b405df1d5a24049dc33d324fe448dc572e561a7b772ae982692900b1a5960901cc4fc7def25a629b9c69a4208ee89d12ab3332617a 399 | languageName: node 400 | linkType: hard 401 | 402 | "code-excerpt@npm:^4.0.0": 403 | version: 4.0.0 404 | resolution: "code-excerpt@npm:4.0.0" 405 | dependencies: 406 | convert-to-spaces: "npm:^2.0.1" 407 | checksum: d57137d8f4825879283a828cc02a1115b56858dc54ed06c625c8f67d6685d1becd2fbaa7f0ab19ecca1f5cca03f8c97bbc1f013cab40261e4d3275032e65efe9 408 | languageName: node 409 | linkType: hard 410 | 411 | "colors@npm:^1.4.0": 412 | version: 1.4.0 413 | resolution: "colors@npm:1.4.0" 414 | checksum: 90b2d5465159813a3983ea72ca8cff75f784824ad70f2cc2b32c233e95bcfbcda101ebc6d6766bc50f57263792629bfb4f1f8a4dfbd1d240f229fc7f69b785fc 415 | languageName: node 416 | linkType: hard 417 | 418 | "commander@npm:^10.0.0": 419 | version: 10.0.1 420 | resolution: "commander@npm:10.0.1" 421 | checksum: 8799faa84a30da985802e661cc9856adfaee324d4b138413013ef7f087e8d7924b144c30a1f1405475f0909f467665cd9e1ce13270a2f41b141dab0b7a58f3fb 422 | languageName: node 423 | linkType: hard 424 | 425 | "convert-to-spaces@npm:^2.0.1": 426 | version: 2.0.1 427 | resolution: "convert-to-spaces@npm:2.0.1" 428 | checksum: bbb324e5916fe9866f65c0ff5f9c1ea933764d0bdb09fccaf59542e40545ed483db6b2339c6d9eb56a11965a58f1a6038f3174f0e2fb7601343c7107ca5e2751 429 | languageName: node 430 | linkType: hard 431 | 432 | "create-require@npm:^1.1.0": 433 | version: 1.1.1 434 | resolution: "create-require@npm:1.1.1" 435 | checksum: a9a1503d4390d8b59ad86f4607de7870b39cad43d929813599a23714831e81c520bddf61bcdd1f8e30f05fd3a2b71ae8538e946eb2786dc65c2bbc520f692eff 436 | languageName: node 437 | linkType: hard 438 | 439 | "cross-spawn@npm:^7.0.3": 440 | version: 7.0.3 441 | resolution: "cross-spawn@npm:7.0.3" 442 | dependencies: 443 | path-key: "npm:^3.1.0" 444 | shebang-command: "npm:^2.0.0" 445 | which: "npm:^2.0.1" 446 | checksum: e1a13869d2f57d974de0d9ef7acbf69dc6937db20b918525a01dacb5032129bd552d290d886d981e99f1b624cb03657084cc87bd40f115c07ecf376821c729ce 447 | languageName: node 448 | linkType: hard 449 | 450 | "csstype@npm:^3.0.2": 451 | version: 3.0.7 452 | resolution: "csstype@npm:3.0.7" 453 | checksum: a93533d9ff044690ad6403b8915db36d667c2a58024fa8b36f398271bb96a132d65cde5d95d0116428311e614193099fdc87e41db076ad923444f0fdceea1282 454 | languageName: node 455 | linkType: hard 456 | 457 | "debug@npm:^4.1.1, debug@npm:^4.3.4": 458 | version: 4.3.4 459 | resolution: "debug@npm:4.3.4" 460 | dependencies: 461 | ms: "npm:2.1.2" 462 | peerDependenciesMeta: 463 | supports-color: 464 | optional: true 465 | checksum: 0073c3bcbd9cb7d71dd5f6b55be8701af42df3e56e911186dfa46fac3a5b9eb7ce7f377dd1d3be6db8977221f8eb333d945216f645cf56f6b688cd484837d255 466 | languageName: node 467 | linkType: hard 468 | 469 | "deprecation@npm:^2.0.0": 470 | version: 2.3.1 471 | resolution: "deprecation@npm:2.3.1" 472 | checksum: f56a05e182c2c195071385455956b0c4106fe14e36245b00c689ceef8e8ab639235176a96977ba7c74afb173317fac2e0ec6ec7a1c6d1e6eaa401c586c714132 473 | languageName: node 474 | linkType: hard 475 | 476 | "diff@npm:^4.0.1": 477 | version: 4.0.2 478 | resolution: "diff@npm:4.0.2" 479 | checksum: ec09ec2101934ca5966355a229d77afcad5911c92e2a77413efda5455636c4cf2ce84057e2d7715227a2eeeda04255b849bd3ae3a4dd22eb22e86e76456df069 480 | languageName: node 481 | linkType: hard 482 | 483 | "eastasianwidth@npm:^0.2.0": 484 | version: 0.2.0 485 | resolution: "eastasianwidth@npm:0.2.0" 486 | checksum: 9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 487 | languageName: node 488 | linkType: hard 489 | 490 | "emoji-regex@npm:^9.2.2": 491 | version: 9.2.2 492 | resolution: "emoji-regex@npm:9.2.2" 493 | checksum: 915acf859cea7131dac1b2b5c9c8e35c4849e325a1d114c30adb8cd615970f6dca0e27f64f3a4949d7d6ed86ecd79a1c5c63f02e697513cddd7b5835c90948b8 494 | languageName: node 495 | linkType: hard 496 | 497 | "escape-string-regexp@npm:^2.0.0": 498 | version: 2.0.0 499 | resolution: "escape-string-regexp@npm:2.0.0" 500 | checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 501 | languageName: node 502 | linkType: hard 503 | 504 | "escape-string-regexp@npm:^5.0.0": 505 | version: 5.0.0 506 | resolution: "escape-string-regexp@npm:5.0.0" 507 | checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e 508 | languageName: node 509 | linkType: hard 510 | 511 | "execa@npm:^5.1.1": 512 | version: 5.1.1 513 | resolution: "execa@npm:5.1.1" 514 | dependencies: 515 | cross-spawn: "npm:^7.0.3" 516 | get-stream: "npm:^6.0.0" 517 | human-signals: "npm:^2.1.0" 518 | is-stream: "npm:^2.0.0" 519 | merge-stream: "npm:^2.0.0" 520 | npm-run-path: "npm:^4.0.1" 521 | onetime: "npm:^5.1.2" 522 | signal-exit: "npm:^3.0.3" 523 | strip-final-newline: "npm:^2.0.0" 524 | checksum: 8ada91f2d70f7dff702c861c2c64f21dfdc1525628f3c0454fd6f02fce65f7b958616cbd2b99ca7fa4d474e461a3d363824e91b3eb881705231abbf387470597 525 | languageName: node 526 | linkType: hard 527 | 528 | "figures@npm:^5.0.0": 529 | version: 5.0.0 530 | resolution: "figures@npm:5.0.0" 531 | dependencies: 532 | escape-string-regexp: "npm:^5.0.0" 533 | is-unicode-supported: "npm:^1.2.0" 534 | checksum: 951d18be2f450c90462c484eff9bda705293319bc2f17b250194a0cf1a291600db4cb283a6ce199d49380c95b08d85d822ce4b18d2f9242663fd5895476d667c 535 | languageName: node 536 | linkType: hard 537 | 538 | "fs-extra@npm:^11.1.1": 539 | version: 11.2.0 540 | resolution: "fs-extra@npm:11.2.0" 541 | dependencies: 542 | graceful-fs: "npm:^4.2.0" 543 | jsonfile: "npm:^6.0.1" 544 | universalify: "npm:^2.0.0" 545 | checksum: 0579bf6726a4cd054d4aa308f10b483f52478bb16284f32cf60b4ce0542063d551fca1a08a2af365e35db21a3fa5a06cf2a6ed614004b4368982bc754cb816b3 546 | languageName: node 547 | linkType: hard 548 | 549 | "fs.realpath@npm:^1.0.0": 550 | version: 1.0.0 551 | resolution: "fs.realpath@npm:1.0.0" 552 | checksum: e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96 553 | languageName: node 554 | linkType: hard 555 | 556 | "get-stream@npm:^6.0.0": 557 | version: 6.0.1 558 | resolution: "get-stream@npm:6.0.1" 559 | checksum: 781266d29725f35c59f1d214aedc92b0ae855800a980800e2923b3fbc4e56b3cb6e462c42e09a1cf1a00c64e056a78fa407cbe06c7c92b7e5cd49b4b85c2a497 560 | languageName: node 561 | linkType: hard 562 | 563 | "glob@npm:^9.3.2": 564 | version: 9.3.5 565 | resolution: "glob@npm:9.3.5" 566 | dependencies: 567 | fs.realpath: "npm:^1.0.0" 568 | minimatch: "npm:^8.0.2" 569 | minipass: "npm:^4.2.4" 570 | path-scurry: "npm:^1.6.1" 571 | checksum: e5fa8a58adf53525bca42d82a1fad9e6800032b7e4d372209b80cfdca524dd9a7dbe7d01a92d7ed20d89c572457f12c250092bc8817cb4f1c63efefdf9b658c0 572 | languageName: node 573 | linkType: hard 574 | 575 | "graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0": 576 | version: 4.2.11 577 | resolution: "graceful-fs@npm:4.2.11" 578 | checksum: bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 579 | languageName: node 580 | linkType: hard 581 | 582 | "human-signals@npm:^2.1.0": 583 | version: 2.1.0 584 | resolution: "human-signals@npm:2.1.0" 585 | checksum: df59be9e0af479036798a881d1f136c4a29e0b518d4abb863afbd11bf30efa3eeb1d0425fc65942dcc05ab3bf40205ea436b0ff389f2cd20b75b8643d539bf86 586 | languageName: node 587 | linkType: hard 588 | 589 | "indent-string@npm:^5.0.0": 590 | version: 5.0.0 591 | resolution: "indent-string@npm:5.0.0" 592 | checksum: e466c27b6373440e6d84fbc19e750219ce25865cb82d578e41a6053d727e5520dc5725217d6eb1cc76005a1bb1696a0f106d84ce7ebda3033b963a38583fb3b3 593 | languageName: node 594 | linkType: hard 595 | 596 | "ink-form@workspace:.": 597 | version: 0.0.0-use.local 598 | resolution: "ink-form@workspace:." 599 | dependencies: 600 | "@types/node": "npm:^14.14.45" 601 | "@types/react": "npm:^18.2.41" 602 | ink: "npm:^4.4.1" 603 | ink-select-input: "npm:^5.0.0" 604 | ink-text-input: "npm:^6.0.0" 605 | prettier: "npm:^2.2.1" 606 | publish-fast: "npm:^0.0.20" 607 | react: "npm:^18.2.0" 608 | ts-node: "npm:^10.9.1" 609 | typedoc: "npm:^0.25.4" 610 | typescript: "npm:^5.3.2" 611 | peerDependencies: 612 | ink: ">=4" 613 | react: ">=18" 614 | languageName: unknown 615 | linkType: soft 616 | 617 | "ink-select-input@npm:^5.0.0": 618 | version: 5.0.0 619 | resolution: "ink-select-input@npm:5.0.0" 620 | dependencies: 621 | arr-rotate: "npm:^1.0.0" 622 | figures: "npm:^5.0.0" 623 | lodash.isequal: "npm:^4.5.0" 624 | peerDependencies: 625 | ink: ^4.0.0 626 | react: ^18.0.0 627 | checksum: 9e21351f7ae1ad1721eca04038e25afd4b6f85ea0abd51235db2ed6894e209198687924a2ae8aca972571cb0601d735810c462676b7ebfd68ae3cafd0d67613c 628 | languageName: node 629 | linkType: hard 630 | 631 | "ink-text-input@npm:^6.0.0": 632 | version: 6.0.0 633 | resolution: "ink-text-input@npm:6.0.0" 634 | dependencies: 635 | chalk: "npm:^5.3.0" 636 | type-fest: "npm:^4.18.2" 637 | peerDependencies: 638 | ink: ">=5" 639 | react: ">=18" 640 | checksum: dc2511df2bf6a93a7ee94efce03eb7fb99028d378bd5446047fa9f4c13de67e8651e9fc89331cc3d158ca84974dfdd2df465a52e241a070cdc3f85048a707931 641 | languageName: node 642 | linkType: hard 643 | 644 | "ink@npm:^4.4.1": 645 | version: 4.4.1 646 | resolution: "ink@npm:4.4.1" 647 | dependencies: 648 | "@alcalzone/ansi-tokenize": "npm:^0.1.3" 649 | ansi-escapes: "npm:^6.0.0" 650 | auto-bind: "npm:^5.0.1" 651 | chalk: "npm:^5.2.0" 652 | cli-boxes: "npm:^3.0.0" 653 | cli-cursor: "npm:^4.0.0" 654 | cli-truncate: "npm:^3.1.0" 655 | code-excerpt: "npm:^4.0.0" 656 | indent-string: "npm:^5.0.0" 657 | is-ci: "npm:^3.0.1" 658 | is-lower-case: "npm:^2.0.2" 659 | is-upper-case: "npm:^2.0.2" 660 | lodash: "npm:^4.17.21" 661 | patch-console: "npm:^2.0.0" 662 | react-reconciler: "npm:^0.29.0" 663 | scheduler: "npm:^0.23.0" 664 | signal-exit: "npm:^3.0.7" 665 | slice-ansi: "npm:^6.0.0" 666 | stack-utils: "npm:^2.0.6" 667 | string-width: "npm:^5.1.2" 668 | type-fest: "npm:^0.12.0" 669 | widest-line: "npm:^4.0.1" 670 | wrap-ansi: "npm:^8.1.0" 671 | ws: "npm:^8.12.0" 672 | yoga-wasm-web: "npm:~0.3.3" 673 | peerDependencies: 674 | "@types/react": ">=18.0.0" 675 | react: ">=18.0.0" 676 | react-devtools-core: ^4.19.1 677 | peerDependenciesMeta: 678 | "@types/react": 679 | optional: true 680 | react-devtools-core: 681 | optional: true 682 | checksum: c432103dbdebdfaea344a2b940be08031533da1d1a4d43cb1d128f0d5fca29831b7b69ad13a71d49afc59ae2e4324185b2f5a7432391764c4078892a9b61c125 683 | languageName: node 684 | linkType: hard 685 | 686 | "is-ci@npm:^3.0.1": 687 | version: 3.0.1 688 | resolution: "is-ci@npm:3.0.1" 689 | dependencies: 690 | ci-info: "npm:^3.2.0" 691 | bin: 692 | is-ci: bin.js 693 | checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e 694 | languageName: node 695 | linkType: hard 696 | 697 | "is-fullwidth-code-point@npm:^4.0.0": 698 | version: 4.0.0 699 | resolution: "is-fullwidth-code-point@npm:4.0.0" 700 | checksum: 8ae89bf5057bdf4f57b346fb6c55e9c3dd2549983d54191d722d5c739397a903012cc41a04ee3403fd872e811243ef91a7c5196da7b5841dc6b6aae31a264a8d 701 | languageName: node 702 | linkType: hard 703 | 704 | "is-lower-case@npm:^2.0.2": 705 | version: 2.0.2 706 | resolution: "is-lower-case@npm:2.0.2" 707 | dependencies: 708 | tslib: "npm:^2.0.3" 709 | checksum: ba57dd1201e15fd9b590654736afccf1b3b68e919f40c23ef13b00ebcc639b1d9c2f81fe86415bff3e8eccffec459786c9ac9dc8f3a19cfa4484206c411c1d7d 710 | languageName: node 711 | linkType: hard 712 | 713 | "is-plain-object@npm:^5.0.0": 714 | version: 5.0.0 715 | resolution: "is-plain-object@npm:5.0.0" 716 | checksum: e32d27061eef62c0847d303125440a38660517e586f2f3db7c9d179ae5b6674ab0f469d519b2e25c147a1a3bc87156d0d5f4d8821e0ce4a9ee7fe1fcf11ce45c 717 | languageName: node 718 | linkType: hard 719 | 720 | "is-stream@npm:^2.0.0": 721 | version: 2.0.1 722 | resolution: "is-stream@npm:2.0.1" 723 | checksum: b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 724 | languageName: node 725 | linkType: hard 726 | 727 | "is-unicode-supported@npm:^1.2.0": 728 | version: 1.3.0 729 | resolution: "is-unicode-supported@npm:1.3.0" 730 | checksum: 20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc 731 | languageName: node 732 | linkType: hard 733 | 734 | "is-upper-case@npm:^2.0.2": 735 | version: 2.0.2 736 | resolution: "is-upper-case@npm:2.0.2" 737 | dependencies: 738 | tslib: "npm:^2.0.3" 739 | checksum: cf4fd43c00c2e72cd5cff911923070b89f0933b464941bd782e2315385f80b5a5acd772db3b796542e5e3cfed735f4dffd88c54d62db1ebfc5c3daa7b1af2bc6 740 | languageName: node 741 | linkType: hard 742 | 743 | "isexe@npm:^2.0.0": 744 | version: 2.0.0 745 | resolution: "isexe@npm:2.0.0" 746 | checksum: 7c9f715c03aff08f35e98b1fadae1b9267b38f0615d501824f9743f3aab99ef10e303ce7db3f186763a0b70a19de5791ebfc854ff884d5a8c4d92211f642ec92 747 | languageName: node 748 | linkType: hard 749 | 750 | "js-tokens@npm:^3.0.0 || ^4.0.0": 751 | version: 4.0.0 752 | resolution: "js-tokens@npm:4.0.0" 753 | checksum: af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 754 | languageName: node 755 | linkType: hard 756 | 757 | "jsonc-parser@npm:^3.2.0": 758 | version: 3.2.0 759 | resolution: "jsonc-parser@npm:3.2.0" 760 | checksum: bd68b902e5f9394f01da97921f49c5084b2dc03a0c5b4fdb2a429f8d6f292686c1bf87badaeb0a8148d024192a88f5ad2e57b2918ba43fe25cf15f3371db64d4 761 | languageName: node 762 | linkType: hard 763 | 764 | "jsonfile@npm:^6.0.1": 765 | version: 6.1.0 766 | resolution: "jsonfile@npm:6.1.0" 767 | dependencies: 768 | graceful-fs: "npm:^4.1.6" 769 | universalify: "npm:^2.0.0" 770 | dependenciesMeta: 771 | graceful-fs: 772 | optional: true 773 | checksum: 03014769e7dc77d4cf05fa0b534907270b60890085dd5e4d60a382ff09328580651da0b8b4cdf44d91e4c8ae64d91791d965f05707beff000ed494a38b6fec85 774 | languageName: node 775 | linkType: hard 776 | 777 | "kleur@npm:^3.0.3": 778 | version: 3.0.3 779 | resolution: "kleur@npm:3.0.3" 780 | checksum: 0c0ecaf00a5c6173d25059c7db2113850b5457016dfa1d0e3ef26da4704fbb186b4938d7611246d86f0ddf1bccf26828daa5877b1f232a65e7373d0122a83e7f 781 | languageName: node 782 | linkType: hard 783 | 784 | "lodash.isequal@npm:^4.5.0": 785 | version: 4.5.0 786 | resolution: "lodash.isequal@npm:4.5.0" 787 | checksum: 82fc58a83a1555f8df34ca9a2cd300995ff94018ac12cc47c349655f0ae1d4d92ba346db4c19bbfc90510764e0c00ddcc985a358bdcd4b3b965abf8f2a48a214 788 | languageName: node 789 | linkType: hard 790 | 791 | "lodash@npm:^4.17.21": 792 | version: 4.17.21 793 | resolution: "lodash@npm:4.17.21" 794 | checksum: c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532 795 | languageName: node 796 | linkType: hard 797 | 798 | "loose-envify@npm:^1.1.0": 799 | version: 1.4.0 800 | resolution: "loose-envify@npm:1.4.0" 801 | dependencies: 802 | js-tokens: "npm:^3.0.0 || ^4.0.0" 803 | bin: 804 | loose-envify: cli.js 805 | checksum: 6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 806 | languageName: node 807 | linkType: hard 808 | 809 | "lru-cache@npm:^10.2.0": 810 | version: 10.2.2 811 | resolution: "lru-cache@npm:10.2.2" 812 | checksum: ff1a496d30b5eaec2c9079080965bb0cede203cf878371f7033a007f1e54cd4aa13cc8abf7ccec4c994a83a22ed5476e83a55bb57cc07e6c1547a42937e42c37 813 | languageName: node 814 | linkType: hard 815 | 816 | "lunr@npm:^2.3.9": 817 | version: 2.3.9 818 | resolution: "lunr@npm:2.3.9" 819 | checksum: f2f6db34c046f5a767782fe2454e6dd69c75ba3c5cf5c1cb9cacca2313a99c2ba78ff8fa67dac866fb7c4ffd5f22e06684793f5f15ba14bddb598b94513d54bf 820 | languageName: node 821 | linkType: hard 822 | 823 | "make-error@npm:^1.1.1": 824 | version: 1.3.6 825 | resolution: "make-error@npm:1.3.6" 826 | checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 827 | languageName: node 828 | linkType: hard 829 | 830 | "marked@npm:^4.3.0": 831 | version: 4.3.0 832 | resolution: "marked@npm:4.3.0" 833 | bin: 834 | marked: bin/marked.js 835 | checksum: c830bb4cb3705b754ca342b656e8a582d7428706b2678c898b856f6030c134ce2d1e19136efa3e6a1841f7330efbd24963d6bdeddc57d2938e906250f99895d0 836 | languageName: node 837 | linkType: hard 838 | 839 | "merge-stream@npm:^2.0.0": 840 | version: 2.0.0 841 | resolution: "merge-stream@npm:2.0.0" 842 | checksum: 6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 843 | languageName: node 844 | linkType: hard 845 | 846 | "mime@npm:^3.0.0": 847 | version: 3.0.0 848 | resolution: "mime@npm:3.0.0" 849 | bin: 850 | mime: cli.js 851 | checksum: b2d31580deb58be89adaa1877cbbf152b7604b980fd7ef8f08b9e96bfedf7d605d9c23a8ba62aa12c8580b910cd7c1d27b7331d0f40f7a14e17d5a0bbec3b49f 852 | languageName: node 853 | linkType: hard 854 | 855 | "mimic-fn@npm:^2.1.0": 856 | version: 2.1.0 857 | resolution: "mimic-fn@npm:2.1.0" 858 | checksum: d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a 859 | languageName: node 860 | linkType: hard 861 | 862 | "minimatch@npm:^8.0.2": 863 | version: 8.0.4 864 | resolution: "minimatch@npm:8.0.4" 865 | dependencies: 866 | brace-expansion: "npm:^2.0.1" 867 | checksum: aef05598ee565e1013bc8a10f53410ac681561f901c1a084b8ecfd016c9ed919f58f4bbd5b63e05643189dfb26e8106a84f0e1ff12e4a263aa37e1cae7ce9828 868 | languageName: node 869 | linkType: hard 870 | 871 | "minimatch@npm:^9.0.3": 872 | version: 9.0.3 873 | resolution: "minimatch@npm:9.0.3" 874 | dependencies: 875 | brace-expansion: "npm:^2.0.1" 876 | checksum: c81b47d28153e77521877649f4bab48348d10938df9e8147a58111fe00ef89559a2938de9f6632910c4f7bf7bb5cd81191a546167e58d357f0cfb1e18cecc1c5 877 | languageName: node 878 | linkType: hard 879 | 880 | "minipass@npm:^4.2.4": 881 | version: 4.2.8 882 | resolution: "minipass@npm:4.2.8" 883 | checksum: e148eb6dcb85c980234cad889139ef8ddf9d5bdac534f4f0268446c8792dd4c74f4502479be48de3c1cce2f6450f6da4d0d4a86405a8a12be04c1c36b339569a 884 | languageName: node 885 | linkType: hard 886 | 887 | "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": 888 | version: 7.1.1 889 | resolution: "minipass@npm:7.1.1" 890 | checksum: 6f4f920f1b5ea585d08fa3739b9bd81726cd85a0c972fb371c0fa6c1544d468813fb1694c7bc64ad81f138fd8abf665e2af0f406de9ba5741d8e4a377ed346b1 891 | languageName: node 892 | linkType: hard 893 | 894 | "ms@npm:2.1.2": 895 | version: 2.1.2 896 | resolution: "ms@npm:2.1.2" 897 | checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f 898 | languageName: node 899 | linkType: hard 900 | 901 | "node-fetch@npm:^2.6.7": 902 | version: 2.7.0 903 | resolution: "node-fetch@npm:2.7.0" 904 | dependencies: 905 | whatwg-url: "npm:^5.0.0" 906 | peerDependencies: 907 | encoding: ^0.1.0 908 | peerDependenciesMeta: 909 | encoding: 910 | optional: true 911 | checksum: b24f8a3dc937f388192e59bcf9d0857d7b6940a2496f328381641cb616efccc9866e89ec43f2ec956bbd6c3d3ee05524ce77fe7b29ccd34692b3a16f237d6676 912 | languageName: node 913 | linkType: hard 914 | 915 | "npm-run-path@npm:^4.0.1": 916 | version: 4.0.1 917 | resolution: "npm-run-path@npm:4.0.1" 918 | dependencies: 919 | path-key: "npm:^3.0.0" 920 | checksum: 5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 921 | languageName: node 922 | linkType: hard 923 | 924 | "once@npm:^1.4.0": 925 | version: 1.4.0 926 | resolution: "once@npm:1.4.0" 927 | dependencies: 928 | wrappy: "npm:1" 929 | checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 930 | languageName: node 931 | linkType: hard 932 | 933 | "onetime@npm:^5.1.0, onetime@npm:^5.1.2": 934 | version: 5.1.2 935 | resolution: "onetime@npm:5.1.2" 936 | dependencies: 937 | mimic-fn: "npm:^2.1.0" 938 | checksum: e9fd0695a01cf226652f0385bf16b7a24153dbbb2039f764c8ba6d2306a8506b0e4ce570de6ad99c7a6eb49520743afdb66edd95ee979c1a342554ed49a9aadd 939 | languageName: node 940 | linkType: hard 941 | 942 | "patch-console@npm:^2.0.0": 943 | version: 2.0.0 944 | resolution: "patch-console@npm:2.0.0" 945 | checksum: 10e7d382cc1cf930a2114a822cdc816109a1147bcbc4881ca4fa2ad0228a60cf14d53f815fce3164f25851fea71db4026ae8271e4026b42b0a6e92ddc074d4c2 946 | languageName: node 947 | linkType: hard 948 | 949 | "path-key@npm:^3.0.0, path-key@npm:^3.1.0": 950 | version: 3.1.1 951 | resolution: "path-key@npm:3.1.1" 952 | checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 953 | languageName: node 954 | linkType: hard 955 | 956 | "path-scurry@npm:^1.6.1": 957 | version: 1.11.1 958 | resolution: "path-scurry@npm:1.11.1" 959 | dependencies: 960 | lru-cache: "npm:^10.2.0" 961 | minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" 962 | checksum: 5e8845c159261adda6f09814d7725683257fcc85a18f329880ab4d7cc1d12830967eae5d5894e453f341710d5484b8fdbbd4d75181b4d6e1eb2f4dc7aeadc434 963 | languageName: node 964 | linkType: hard 965 | 966 | "prettier@npm:^2.2.1": 967 | version: 2.2.1 968 | resolution: "prettier@npm:2.2.1" 969 | bin: 970 | prettier: bin-prettier.js 971 | checksum: 7bad7ef9cf2da3059a83de0729d480879f5adbe9974419a16a953dee69b2c720ebf1df8d1a713306547a5af8c2b6168a79cd94bda15202de0121348123f7903f 972 | languageName: node 973 | linkType: hard 974 | 975 | "prompts@npm:^2.4.2": 976 | version: 2.4.2 977 | resolution: "prompts@npm:2.4.2" 978 | dependencies: 979 | kleur: "npm:^3.0.3" 980 | sisteransi: "npm:^1.0.5" 981 | checksum: c52536521a4d21eff4f2f2aa4572446cad227464066365a7167e52ccf8d9839c099f9afec1aba0eed3d5a2514b3e79e0b3e7a1dc326b9acde6b75d27ed74b1a9 982 | languageName: node 983 | linkType: hard 984 | 985 | "publish-fast@npm:^0.0.20": 986 | version: 0.0.20 987 | resolution: "publish-fast@npm:0.0.20" 988 | dependencies: 989 | "@octokit/rest": "npm:^19.0.7" 990 | colors: "npm:^1.4.0" 991 | commander: "npm:^10.0.0" 992 | execa: "npm:^5.1.1" 993 | fs-extra: "npm:^11.1.1" 994 | glob: "npm:^9.3.2" 995 | mime: "npm:^3.0.0" 996 | prompts: "npm:^2.4.2" 997 | semver: "npm:^7.3.8" 998 | simple-git: "npm:^3.17.0" 999 | bin: 1000 | publish-fast: lib/cjs/index.js 1001 | checksum: 8ab904643173787b15a6ecdf99bc2de557e24935a0ba1b538a23b71e2ea8e49eb3108ceca0099813d95f31a9f332b15c6129073115c6c6e55d47acfc7ec5b794 1002 | languageName: node 1003 | linkType: hard 1004 | 1005 | "react-reconciler@npm:^0.29.0": 1006 | version: 0.29.0 1007 | resolution: "react-reconciler@npm:0.29.0" 1008 | dependencies: 1009 | loose-envify: "npm:^1.1.0" 1010 | scheduler: "npm:^0.23.0" 1011 | peerDependencies: 1012 | react: ^18.2.0 1013 | checksum: 71f69399152a47fa51aa39e35c1d680906ae089fe932725f62b20b9af9a1b232575fc21f7a4d9aad789a401094d674d0ecabaffb0b9a2dab67edc6069854aae3 1014 | languageName: node 1015 | linkType: hard 1016 | 1017 | "react@npm:^18.2.0": 1018 | version: 18.2.0 1019 | resolution: "react@npm:18.2.0" 1020 | dependencies: 1021 | loose-envify: "npm:^1.1.0" 1022 | checksum: b9214a9bd79e99d08de55f8bef2b7fc8c39630be97c4e29d7be173d14a9a10670b5325e94485f74cd8bff4966ef3c78ee53c79a7b0b9b70cba20aa8973acc694 1023 | languageName: node 1024 | linkType: hard 1025 | 1026 | "restore-cursor@npm:^4.0.0": 1027 | version: 4.0.0 1028 | resolution: "restore-cursor@npm:4.0.0" 1029 | dependencies: 1030 | onetime: "npm:^5.1.0" 1031 | signal-exit: "npm:^3.0.2" 1032 | checksum: 5b675c5a59763bf26e604289eab35711525f11388d77f409453904e1e69c0d37ae5889295706b2c81d23bd780165084d040f9b68fffc32cc921519031c4fa4af 1033 | languageName: node 1034 | linkType: hard 1035 | 1036 | "scheduler@npm:^0.23.0": 1037 | version: 0.23.0 1038 | resolution: "scheduler@npm:0.23.0" 1039 | dependencies: 1040 | loose-envify: "npm:^1.1.0" 1041 | checksum: 0c4557aa37bafca44ff21dc0ea7c92e2dbcb298bc62eae92b29a39b029134f02fb23917d6ebc8b1fa536b4184934314c20d8864d156a9f6357f3398aaf7bfda8 1042 | languageName: node 1043 | linkType: hard 1044 | 1045 | "semver@npm:^7.3.8": 1046 | version: 7.6.2 1047 | resolution: "semver@npm:7.6.2" 1048 | bin: 1049 | semver: bin/semver.js 1050 | checksum: 296b17d027f57a87ef645e9c725bff4865a38dfc9caf29b26aa084b85820972fbe7372caea1ba6857162fa990702c6d9c1d82297cecb72d56c78ab29070d2ca2 1051 | languageName: node 1052 | linkType: hard 1053 | 1054 | "shebang-command@npm:^2.0.0": 1055 | version: 2.0.0 1056 | resolution: "shebang-command@npm:2.0.0" 1057 | dependencies: 1058 | shebang-regex: "npm:^3.0.0" 1059 | checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa 1060 | languageName: node 1061 | linkType: hard 1062 | 1063 | "shebang-regex@npm:^3.0.0": 1064 | version: 3.0.0 1065 | resolution: "shebang-regex@npm:3.0.0" 1066 | checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 1067 | languageName: node 1068 | linkType: hard 1069 | 1070 | "shiki@npm:^0.14.1": 1071 | version: 0.14.5 1072 | resolution: "shiki@npm:0.14.5" 1073 | dependencies: 1074 | ansi-sequence-parser: "npm:^1.1.0" 1075 | jsonc-parser: "npm:^3.2.0" 1076 | vscode-oniguruma: "npm:^1.7.0" 1077 | vscode-textmate: "npm:^8.0.0" 1078 | checksum: 02c96cf7efcf71679e5c0d58eb91fea6a680251cadcbb15b7a3ccff38004382d3a6d0fdf4a336c2ecda6f6beb50eb9658d3ce91111196621df4fb18bbe4d334e 1079 | languageName: node 1080 | linkType: hard 1081 | 1082 | "signal-exit@npm:^3.0.2": 1083 | version: 3.0.3 1084 | resolution: "signal-exit@npm:3.0.3" 1085 | checksum: f0169d3f1263d06df32ca072b0bf33b34c6f8f0341a7a1621558a2444dfbe8f5fec76b35537fcc6f0bc4944bdb5336fe0bdcf41a5422c4e45a1dba3f45475e6c 1086 | languageName: node 1087 | linkType: hard 1088 | 1089 | "signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": 1090 | version: 3.0.7 1091 | resolution: "signal-exit@npm:3.0.7" 1092 | checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 1093 | languageName: node 1094 | linkType: hard 1095 | 1096 | "simple-git@npm:^3.17.0": 1097 | version: 3.24.0 1098 | resolution: "simple-git@npm:3.24.0" 1099 | dependencies: 1100 | "@kwsites/file-exists": "npm:^1.1.1" 1101 | "@kwsites/promise-deferred": "npm:^1.1.1" 1102 | debug: "npm:^4.3.4" 1103 | checksum: be1b93c799cbb1daa6ceb0c9b8a5a501026c7add69cadf50b10e74fd03bdc801a582c45ff7f69f998c736defd495cc5c5840e95d069e0fb4ed5014e8af0abaf6 1104 | languageName: node 1105 | linkType: hard 1106 | 1107 | "sisteransi@npm:^1.0.5": 1108 | version: 1.0.5 1109 | resolution: "sisteransi@npm:1.0.5" 1110 | checksum: aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 1111 | languageName: node 1112 | linkType: hard 1113 | 1114 | "slice-ansi@npm:^5.0.0": 1115 | version: 5.0.0 1116 | resolution: "slice-ansi@npm:5.0.0" 1117 | dependencies: 1118 | ansi-styles: "npm:^6.0.0" 1119 | is-fullwidth-code-point: "npm:^4.0.0" 1120 | checksum: 7e600a2a55e333a21ef5214b987c8358fe28bfb03c2867ff2cbf919d62143d1812ac27b4297a077fdaf27a03da3678e49551c93e35f9498a3d90221908a1180e 1121 | languageName: node 1122 | linkType: hard 1123 | 1124 | "slice-ansi@npm:^6.0.0": 1125 | version: 6.0.0 1126 | resolution: "slice-ansi@npm:6.0.0" 1127 | dependencies: 1128 | ansi-styles: "npm:^6.2.1" 1129 | is-fullwidth-code-point: "npm:^4.0.0" 1130 | checksum: d0510f02af166eff9948e7cf88985c33d9ded6de0e39908b67b5e29f802c88025c27d7e1801ce1d1d1ec311fb539538086cd2a4193d2e8f735e6c5c0e63486dd 1131 | languageName: node 1132 | linkType: hard 1133 | 1134 | "stack-utils@npm:^2.0.6": 1135 | version: 2.0.6 1136 | resolution: "stack-utils@npm:2.0.6" 1137 | dependencies: 1138 | escape-string-regexp: "npm:^2.0.0" 1139 | checksum: cdc988acbc99075b4b036ac6014e5f1e9afa7e564482b687da6384eee6a1909d7eaffde85b0a17ffbe186c5247faf6c2b7544e802109f63b72c7be69b13151bb 1140 | languageName: node 1141 | linkType: hard 1142 | 1143 | "string-width@npm:^5.0.0, string-width@npm:^5.0.1, string-width@npm:^5.1.2": 1144 | version: 5.1.2 1145 | resolution: "string-width@npm:5.1.2" 1146 | dependencies: 1147 | eastasianwidth: "npm:^0.2.0" 1148 | emoji-regex: "npm:^9.2.2" 1149 | strip-ansi: "npm:^7.0.1" 1150 | checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 1151 | languageName: node 1152 | linkType: hard 1153 | 1154 | "strip-ansi@npm:^7.0.1": 1155 | version: 7.1.0 1156 | resolution: "strip-ansi@npm:7.1.0" 1157 | dependencies: 1158 | ansi-regex: "npm:^6.0.1" 1159 | checksum: 475f53e9c44375d6e72807284024ac5d668ee1d06010740dec0b9744f2ddf47de8d7151f80e5f6190fc8f384e802fdf9504b76a7e9020c9faee7103623338be2 1160 | languageName: node 1161 | linkType: hard 1162 | 1163 | "strip-final-newline@npm:^2.0.0": 1164 | version: 2.0.0 1165 | resolution: "strip-final-newline@npm:2.0.0" 1166 | checksum: 69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 1167 | languageName: node 1168 | linkType: hard 1169 | 1170 | "tr46@npm:~0.0.3": 1171 | version: 0.0.3 1172 | resolution: "tr46@npm:0.0.3" 1173 | checksum: 8f1f5aa6cb232f9e1bdc86f485f916b7aa38caee8a778b378ffec0b70d9307873f253f5cbadbe2955ece2ac5c83d0dc14a77513166ccd0a0c7fe197e21396695 1174 | languageName: node 1175 | linkType: hard 1176 | 1177 | "ts-node@npm:^10.9.1": 1178 | version: 10.9.1 1179 | resolution: "ts-node@npm:10.9.1" 1180 | dependencies: 1181 | "@cspotcode/source-map-support": "npm:^0.8.0" 1182 | "@tsconfig/node10": "npm:^1.0.7" 1183 | "@tsconfig/node12": "npm:^1.0.7" 1184 | "@tsconfig/node14": "npm:^1.0.0" 1185 | "@tsconfig/node16": "npm:^1.0.2" 1186 | acorn: "npm:^8.4.1" 1187 | acorn-walk: "npm:^8.1.1" 1188 | arg: "npm:^4.1.0" 1189 | create-require: "npm:^1.1.0" 1190 | diff: "npm:^4.0.1" 1191 | make-error: "npm:^1.1.1" 1192 | v8-compile-cache-lib: "npm:^3.0.1" 1193 | yn: "npm:3.1.1" 1194 | peerDependencies: 1195 | "@swc/core": ">=1.2.50" 1196 | "@swc/wasm": ">=1.2.50" 1197 | "@types/node": "*" 1198 | typescript: ">=2.7" 1199 | peerDependenciesMeta: 1200 | "@swc/core": 1201 | optional: true 1202 | "@swc/wasm": 1203 | optional: true 1204 | bin: 1205 | ts-node: dist/bin.js 1206 | ts-node-cwd: dist/bin-cwd.js 1207 | ts-node-esm: dist/bin-esm.js 1208 | ts-node-script: dist/bin-script.js 1209 | ts-node-transpile-only: dist/bin-transpile.js 1210 | ts-script: dist/bin-script-deprecated.js 1211 | checksum: bee56d4dc96ccbafc99dfab7b73fbabc62abab2562af53cdea91c874a301b9d11e42bc33c0a032a6ed6d813dbdc9295ec73dde7b73ea4ebde02b0e22006f7e04 1212 | languageName: node 1213 | linkType: hard 1214 | 1215 | "tslib@npm:^2.0.3": 1216 | version: 2.6.2 1217 | resolution: "tslib@npm:2.6.2" 1218 | checksum: bd26c22d36736513980091a1e356378e8b662ded04204453d353a7f34a4c21ed0afc59b5f90719d4ba756e581a162ecbf93118dc9c6be5acf70aa309188166ca 1219 | languageName: node 1220 | linkType: hard 1221 | 1222 | "type-fest@npm:^0.12.0": 1223 | version: 0.12.0 1224 | resolution: "type-fest@npm:0.12.0" 1225 | checksum: 828dd234a0497721622de2907147aff3290a42f86ca01b3d1c1273b4f50bcd00eadcb71c7fad9b34125c7796b8d3a554415f9dda4875993ed51636431488f712 1226 | languageName: node 1227 | linkType: hard 1228 | 1229 | "type-fest@npm:^3.0.0": 1230 | version: 3.13.1 1231 | resolution: "type-fest@npm:3.13.1" 1232 | checksum: 9a8a2359ada34c9b3affcaf3a8f73ee14c52779e89950db337ce66fb74c3399776c697c99f2532e9b16e10e61cfdba3b1c19daffb93b338b742f0acd0117ce12 1233 | languageName: node 1234 | linkType: hard 1235 | 1236 | "type-fest@npm:^4.18.2": 1237 | version: 4.18.2 1238 | resolution: "type-fest@npm:4.18.2" 1239 | checksum: 2c176de28384a247fac1503165774e874c15ac39434a775f32ecda3aef5a0cefcfa2f5fb670c3da1f81cf773c355999154078c8d9657db19b65de78334b27933 1240 | languageName: node 1241 | linkType: hard 1242 | 1243 | "typedoc@npm:^0.25.4": 1244 | version: 0.25.4 1245 | resolution: "typedoc@npm:0.25.4" 1246 | dependencies: 1247 | lunr: "npm:^2.3.9" 1248 | marked: "npm:^4.3.0" 1249 | minimatch: "npm:^9.0.3" 1250 | shiki: "npm:^0.14.1" 1251 | peerDependencies: 1252 | typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x 1253 | bin: 1254 | typedoc: bin/typedoc 1255 | checksum: 638f63d751ba86f1b0e04a303501b88b6e97ba093f82c3fa72a555c207e16fd316ec76c13f7d628e9ee26296f80fddc45b87d4b13714925c5e726047adb76d22 1256 | languageName: node 1257 | linkType: hard 1258 | 1259 | "typescript@npm:^5.3.2": 1260 | version: 5.3.2 1261 | resolution: "typescript@npm:5.3.2" 1262 | bin: 1263 | tsc: bin/tsc 1264 | tsserver: bin/tsserver 1265 | checksum: 415e5fb6611f5713e460bad48039f00bcfdbde53a2f911727862d5aa9c5d5edd250059a419df382d8f031709e15a169c41eb62b6a401da5eec7ac0f4e359d6ac 1266 | languageName: node 1267 | linkType: hard 1268 | 1269 | "typescript@patch:typescript@npm%3A^5.3.2#optional!builtin": 1270 | version: 5.3.2 1271 | resolution: "typescript@patch:typescript@npm%3A5.3.2#optional!builtin::version=5.3.2&hash=14eedb" 1272 | bin: 1273 | tsc: bin/tsc 1274 | tsserver: bin/tsserver 1275 | checksum: 43c3346528a1b410b9ee7f218d709ce8d1336eb8e47b0f8bb43954f98ed43fd11e35de398c9a5f4a085b6889c89782362789b00db7aac862bd09d083058a01a2 1276 | languageName: node 1277 | linkType: hard 1278 | 1279 | "universal-user-agent@npm:^6.0.0": 1280 | version: 6.0.1 1281 | resolution: "universal-user-agent@npm:6.0.1" 1282 | checksum: fdc8e1ae48a05decfc7ded09b62071f571c7fe0bd793d700704c80cea316101d4eac15cc27ed2bb64f4ce166d2684777c3198b9ab16034f547abea0d3aa1c93c 1283 | languageName: node 1284 | linkType: hard 1285 | 1286 | "universalify@npm:^2.0.0": 1287 | version: 2.0.1 1288 | resolution: "universalify@npm:2.0.1" 1289 | checksum: ecd8469fe0db28e7de9e5289d32bd1b6ba8f7183db34f3bfc4ca53c49891c2d6aa05f3fb3936a81285a905cc509fb641a0c3fc131ec786167eff41236ae32e60 1290 | languageName: node 1291 | linkType: hard 1292 | 1293 | "v8-compile-cache-lib@npm:^3.0.1": 1294 | version: 3.0.1 1295 | resolution: "v8-compile-cache-lib@npm:3.0.1" 1296 | checksum: 88d3423a52b6aaf1836be779cab12f7016d47ad8430dffba6edf766695e6d90ad4adaa3d8eeb512cc05924f3e246c4a4ca51e089dccf4402caa536b5e5be8961 1297 | languageName: node 1298 | linkType: hard 1299 | 1300 | "vscode-oniguruma@npm:^1.7.0": 1301 | version: 1.7.0 1302 | resolution: "vscode-oniguruma@npm:1.7.0" 1303 | checksum: 7da9d21459f9788544b258a5fd1b9752df6edd8b406a19eea0209c6bf76507d5717277016799301c4da0d536095f9ca8c06afd1ab8f4001189090c804ca4814e 1304 | languageName: node 1305 | linkType: hard 1306 | 1307 | "vscode-textmate@npm:^8.0.0": 1308 | version: 8.0.0 1309 | resolution: "vscode-textmate@npm:8.0.0" 1310 | checksum: 9fa7d66d6042cb090d116c2d8820d34c8870cfcbaed6e404da89f66b899970ed0ac47b59a2e30fc40a25af5414822bb3ea27974f714e9b91910d69c894be95f7 1311 | languageName: node 1312 | linkType: hard 1313 | 1314 | "webidl-conversions@npm:^3.0.0": 1315 | version: 3.0.1 1316 | resolution: "webidl-conversions@npm:3.0.1" 1317 | checksum: b65b9f8d6854572a84a5c69615152b63371395f0c5dcd6729c45789052296df54314db2bc3e977df41705eacb8bc79c247cee139a63fa695192f95816ed528ad 1318 | languageName: node 1319 | linkType: hard 1320 | 1321 | "whatwg-url@npm:^5.0.0": 1322 | version: 5.0.0 1323 | resolution: "whatwg-url@npm:5.0.0" 1324 | dependencies: 1325 | tr46: "npm:~0.0.3" 1326 | webidl-conversions: "npm:^3.0.0" 1327 | checksum: f95adbc1e80820828b45cc671d97da7cd5e4ef9deb426c31bcd5ab00dc7103042291613b3ef3caec0a2335ed09e0d5ed026c940755dbb6d404e2b27f940fdf07 1328 | languageName: node 1329 | linkType: hard 1330 | 1331 | "which@npm:^2.0.1": 1332 | version: 2.0.2 1333 | resolution: "which@npm:2.0.2" 1334 | dependencies: 1335 | isexe: "npm:^2.0.0" 1336 | bin: 1337 | node-which: ./bin/node-which 1338 | checksum: 4782f8a1d6b8fc12c65e968fea49f59752bf6302dc43036c3bf87da718a80710f61a062516e9764c70008b487929a73546125570acea95c5b5dcc8ac3052c70f 1339 | languageName: node 1340 | linkType: hard 1341 | 1342 | "widest-line@npm:^4.0.1": 1343 | version: 4.0.1 1344 | resolution: "widest-line@npm:4.0.1" 1345 | dependencies: 1346 | string-width: "npm:^5.0.1" 1347 | checksum: 64c48cf27171221be5f86fc54b94dd29879165bdff1a7aa92dde723d9a8c99fb108312768a5d62c8c2b80b701fa27bbd36a1ddc58367585cd45c0db7920a0cba 1348 | languageName: node 1349 | linkType: hard 1350 | 1351 | "wrap-ansi@npm:^8.1.0": 1352 | version: 8.1.0 1353 | resolution: "wrap-ansi@npm:8.1.0" 1354 | dependencies: 1355 | ansi-styles: "npm:^6.1.0" 1356 | string-width: "npm:^5.0.1" 1357 | strip-ansi: "npm:^7.0.1" 1358 | checksum: 7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf 1359 | languageName: node 1360 | linkType: hard 1361 | 1362 | "wrappy@npm:1": 1363 | version: 1.0.2 1364 | resolution: "wrappy@npm:1.0.2" 1365 | checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 1366 | languageName: node 1367 | linkType: hard 1368 | 1369 | "ws@npm:^8.12.0": 1370 | version: 8.14.2 1371 | resolution: "ws@npm:8.14.2" 1372 | peerDependencies: 1373 | bufferutil: ^4.0.1 1374 | utf-8-validate: ">=5.0.2" 1375 | peerDependenciesMeta: 1376 | bufferutil: 1377 | optional: true 1378 | utf-8-validate: 1379 | optional: true 1380 | checksum: 815ff01d9bc20a249b2228825d9739268a03a4408c2e0b14d49b0e2ae89d7f10847e813b587ba26992bdc33e9d03bed131e4cae73ff996baf789d53e99c31186 1381 | languageName: node 1382 | linkType: hard 1383 | 1384 | "yn@npm:3.1.1": 1385 | version: 3.1.1 1386 | resolution: "yn@npm:3.1.1" 1387 | checksum: 2c487b0e149e746ef48cda9f8bad10fc83693cd69d7f9dcd8be4214e985de33a29c9e24f3c0d6bcf2288427040a8947406ab27f7af67ee9456e6b84854f02dd6 1388 | languageName: node 1389 | linkType: hard 1390 | 1391 | "yoga-wasm-web@npm:~0.3.3": 1392 | version: 0.3.3 1393 | resolution: "yoga-wasm-web@npm:0.3.3" 1394 | checksum: 7a60a7dbb6dc0383395f2b40c9fac6e4f7b322f934ebb07cefc92997baca597f3ef01f67fe37e5e61c128de917760aa7639980ed2f8d94c2dfbef83bd5f61e36 1395 | languageName: node 1396 | linkType: hard 1397 | --------------------------------------------------------------------------------