diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 9416844..4aea4d4 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/package.json b/package.json index 4029827..4e0b76c 100644 --- a/package.json +++ b/package.json @@ -23,12 +23,16 @@ "build:caret": "cd packages/caret && yarn build", "build:keyboard": "cd packages/keyboard && yarn build", "lint": "eslint", - "lint:fix": "yarn lint --fix" + "lint:fix": "yarn lint --fix", + "generate-docs": "ts-node scripts/generateReadme.ts" }, "devDependencies": { + "@types/fs-extra": "^11", "@types/node": "^20.10.7", "eslint": "^9.0.0", "eslint-config-codex": "^2.0.0", + "fs-extra": "^11.2.0", + "ts-node": "^10.9.2", "typescript": "^5.4.5", "typescript-eslint": "^7.9.0" }, diff --git a/packages/caret/README.md b/packages/caret/README.md new file mode 100644 index 0000000..fbc591f --- /dev/null +++ b/packages/caret/README.md @@ -0,0 +1,23 @@ +# @editorjs/caret +Utils useful for work with caret for Editor.js tools development +### Installation + ``` + npm install @editorjs/caret +``` +### Function list +- [checkContenteditableSliceForEmptiness](https://github.com/editor-js/utils/blob/main/packages/caret/src/checkContenteditableSliceForEmptiness.ts) - Checks content at left or right of the passed node for emptiness. +- [focus](https://github.com/editor-js/utils/blob/main/packages/caret/src/focus.ts) - Set focus to contenteditable or native input element +- [getCaretNodeAndOffset](https://github.com/editor-js/utils/blob/main/packages/caret/src/getCaretNodeAndOffset.ts) - Returns TextNode containing a caret and a caret offset in it +- [getContenteditableSlice](https://github.com/editor-js/utils/blob/main/packages/caret/src/getContenteditableSlice.ts) - Returns slice of the contenteditable html element from caret position to the start or end (depending on direction) +- [getRange](https://github.com/editor-js/utils/blob/main/packages/caret/src/getRange.ts) - Returns the first range +- [isCaretAtEndOfInput](https://github.com/editor-js/utils/blob/main/packages/caret/src/isCaretAtEndOfInput.ts) - Checks if caret is at the end of the passed input +- [isCaretAtStartOfInput](https://github.com/editor-js/utils/blob/main/packages/caret/src/isCaretAtStartOfInput.ts) - Checks if caret is at the start of the passed input +- [save](https://github.com/editor-js/utils/blob/main/packages/caret/src/save.ts) - Saves caret position using hidden +# About CodeX + + + CodeX is a team of digital specialists around the world interested in building high-quality open source products on a global market. We are [open](https://codex.so/join) for young people who want to constantly improve their skills and grow professionally with experiments in cutting-edge technologies. + + | 🌐 | Join 👋 | Twitter | Instagram | + | -- | -- | -- | -- | + | [codex.so](https://codex.so) | [codex.so/join](https://codex.so/join) |[@codex_team](http://twitter.com/codex_team) | [@codex_team](http://instagram.com/codex_team/) | \ No newline at end of file diff --git a/packages/caret/package.json b/packages/caret/package.json index 3ed083a..fdf0327 100644 --- a/packages/caret/package.json +++ b/packages/caret/package.json @@ -1,6 +1,7 @@ { "name": "@editorjs/caret", - "version": "0.0.1", + "description": "Utils useful for work with caret for Editor.js tools development", + "version": "0.0.2", "main": "dist/index.js", "license": "MIT", "scripts": { diff --git a/packages/caret/src/checkContenteditableSliceForEmptiness.ts b/packages/caret/src/checkContenteditableSliceForEmptiness.ts new file mode 100644 index 0000000..511af48 --- /dev/null +++ b/packages/caret/src/checkContenteditableSliceForEmptiness.ts @@ -0,0 +1,22 @@ +import { isCollapsedWhitespaces } from '@editorjs/dom'; +import { getContenteditableSlice } from './getContenteditableSlice'; + +/** + * Checks content at left or right of the passed node for emptiness. + * @param contenteditable - The contenteditable element containing the nodes. + * @param fromNode - The starting node to check from. + * @param offsetInsideNode - The offset inside the starting node. + * @param direction - The direction to check ('left' or 'right'). + * @returns true if adjacent content is empty, false otherwise. + */ +export function checkContenteditableSliceForEmptiness(contenteditable: HTMLElement, fromNode: Node, offsetInsideNode: number, direction: 'left' | 'right'): boolean { + /** + * Get content editable slice + */ + const textContent = getContenteditableSlice(contenteditable, fromNode, offsetInsideNode, direction); + + /** + * Check extracted slice for emptiness + */ + return isCollapsedWhitespaces(textContent); +} diff --git a/packages/caret/src/focus.ts b/packages/caret/src/focus.ts new file mode 100644 index 0000000..066e9b0 --- /dev/null +++ b/packages/caret/src/focus.ts @@ -0,0 +1,29 @@ +import { isNativeInput } from '@editorjs/dom'; + +/** + * Set focus to contenteditable or native input element + * @param element - element where to set focus + * @param atStart - where to set focus: at the start or at the end + */ +export function focus(element: HTMLElement, atStart: boolean = true): void { + /** If element is native input */ + if (isNativeInput(element)) { + element.focus(); + const position = atStart ? 0 : element.value.length; + + element.setSelectionRange(position, position); + } else { + const range = document.createRange(); + const selection = window.getSelection(); + + if (!selection) { + return; + } + + range.selectNodeContents(element); + range.collapse(atStart); + + selection.removeAllRanges(); + selection.addRange(range); + } +} diff --git a/packages/dom/src/checkContenteditableSliceForEmptiness.ts b/packages/caret/src/getContenteditableSlice.ts similarity index 68% rename from packages/dom/src/checkContenteditableSliceForEmptiness.ts rename to packages/caret/src/getContenteditableSlice.ts index 7978494..c5511c2 100644 --- a/packages/dom/src/checkContenteditableSliceForEmptiness.ts +++ b/packages/caret/src/getContenteditableSlice.ts @@ -1,14 +1,15 @@ -import { isCollapsedWhitespaces } from './isCollapsedWhitespaces'; +import { fragmentToString } from '@editorjs/dom'; /** - * Checks content at left or right of the passed node for emptiness. + * Returns slice of the contenteditable html element from caret position to the start or end (depending on direction) * @param contenteditable - The contenteditable element containing the nodes. * @param fromNode - The starting node to check from. * @param offsetInsideNode - The offset inside the starting node. * @param direction - The direction to check ('left' or 'right'). + * @param extract - should we remove from element extracted part * @returns true if adjacent content is empty, false otherwise. */ -export function checkContenteditableSliceForEmptiness(contenteditable: HTMLElement, fromNode: Node, offsetInsideNode: number, direction: 'left' | 'right'): boolean { +export function getContenteditableSlice(contenteditable: HTMLElement, fromNode: Node, offsetInsideNode: number, direction: 'left' | 'right', extract: boolean = false): string { const range = document.createRange(); /** @@ -28,6 +29,15 @@ export function checkContenteditableSliceForEmptiness(contenteditable: HTMLEleme range.setEnd(contenteditable, contenteditable.childNodes.length); } + /** + * Check if we should extract content from the range + */ + if (extract === true) { + const textContent = range.extractContents(); + + return fragmentToString(textContent); + } + /** * Clone the range's content and check its text content */ @@ -45,5 +55,5 @@ export function checkContenteditableSliceForEmptiness(contenteditable: HTMLEleme * * If text contains only invisible whitespaces, it is considered to be empty */ - return isCollapsedWhitespaces(textContent); + return textContent; } diff --git a/packages/caret/src/getRange.ts b/packages/caret/src/getRange.ts new file mode 100644 index 0000000..4673b1e --- /dev/null +++ b/packages/caret/src/getRange.ts @@ -0,0 +1,9 @@ +/** + * Returns the first range + * @returns range of the caret if it exists, null otherwise + */ +export function getRange(): Range | null { + const selection = window.getSelection(); + + return selection && selection.rangeCount ? selection.getRangeAt(0) : null; +} diff --git a/packages/caret/src/index.ts b/packages/caret/src/index.ts index 5298398..5fffd12 100644 --- a/packages/caret/src/index.ts +++ b/packages/caret/src/index.ts @@ -1,7 +1,17 @@ +import { checkContenteditableSliceForEmptiness } from './checkContenteditableSliceForEmptiness'; +import { getContenteditableSlice } from './getContenteditableSlice'; +import { focus } from './focus'; import { getCaretNodeAndOffset } from './getCaretNodeAndOffset'; +import { getRange } from './getRange'; import { isCaretAtEndOfInput } from './isCaretAtEndOfInput'; import { isCaretAtStartOfInput } from './isCaretAtStartOfInput'; +import { save } from './save'; -export { getCaretNodeAndOffset, +export { checkContenteditableSliceForEmptiness, + getContenteditableSlice, + focus, + getCaretNodeAndOffset, + getRange, isCaretAtEndOfInput, - isCaretAtStartOfInput }; + isCaretAtStartOfInput, + save }; diff --git a/packages/caret/src/isCaretAtEndOfInput.ts b/packages/caret/src/isCaretAtEndOfInput.ts index eaec38f..edf846c 100644 --- a/packages/caret/src/isCaretAtEndOfInput.ts +++ b/packages/caret/src/isCaretAtEndOfInput.ts @@ -1,5 +1,7 @@ -import { getDeepestNode, isNativeInput, checkContenteditableSliceForEmptiness } from '@editorjs/dom'; +import { getDeepestNode, isNativeInput } from '@editorjs/dom'; import { getCaretNodeAndOffset } from './getCaretNodeAndOffset'; +import { checkContenteditableSliceForEmptiness } from './checkContenteditableSliceForEmptiness'; + /** * Checks if caret is at the end of the passed input * diff --git a/packages/caret/src/isCaretAtStartOfInput.ts b/packages/caret/src/isCaretAtStartOfInput.ts index b4683c0..fb27f86 100644 --- a/packages/caret/src/isCaretAtStartOfInput.ts +++ b/packages/caret/src/isCaretAtStartOfInput.ts @@ -1,5 +1,6 @@ -import { getDeepestNode, isEmpty, isNativeInput, checkContenteditableSliceForEmptiness } from '@editorjs/dom'; +import { getDeepestNode, isEmpty, isNativeInput } from '@editorjs/dom'; import { getCaretNodeAndOffset } from './getCaretNodeAndOffset'; +import { checkContenteditableSliceForEmptiness } from './checkContenteditableSliceForEmptiness'; /** * Checks if caret is at the start of the passed input diff --git a/packages/caret/src/save.ts b/packages/caret/src/save.ts new file mode 100644 index 0000000..f995062 --- /dev/null +++ b/packages/caret/src/save.ts @@ -0,0 +1,45 @@ +import { make } from '@editorjs/dom'; +import { getRange } from './getRange'; + +/** + * Saves caret position using hidden + * @returns function for resoring the caret + */ +export function save(): () => void { + const range = getRange(); + const caret = make('span'); + + caret.id = 'cursor'; + + caret.hidden = true; + + if (!range) { + return; + } + range.insertNode(caret); + + /** + * Return funciton that will restore caret and delete temporary span element + */ + return function restore(): void { + const sel = window.getSelection(); + + if (!sel) { + return; + } + + range.setStartAfter(caret); + range.setEndAfter(caret); + + sel.removeAllRanges(); + sel.addRange(range); + + /** + * A little timeout uses to allow browser to set caret after element before we remove it. + */ + setTimeout(() => { + caret.remove(); + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + }, 150); + }; +} diff --git a/packages/caret/tsconfig.json b/packages/caret/tsconfig.json index 38db291..579096f 100644 --- a/packages/caret/tsconfig.json +++ b/packages/caret/tsconfig.json @@ -1,5 +1,4 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", "rootDir": "src", diff --git a/packages/dom/README.md b/packages/dom/README.md new file mode 100644 index 0000000..fc44d78 --- /dev/null +++ b/packages/dom/README.md @@ -0,0 +1,40 @@ +# @editorjs/dom +Utils useful for work with dom for Editor.js tools development +### Installation + ``` + npm install @editorjs/dom +``` +### Function list +- [allInputsSelector](https://github.com/editor-js/utils/blob/main/packages/dom/src/allInputsSelector.ts) - Returns CSS selector for all text inputs +- [append](https://github.com/editor-js/utils/blob/main/packages/dom/src/append.ts) - Append one or several elements to the parent +- [blockElements](https://github.com/editor-js/utils/blob/main/packages/dom/src/blockElements.ts) - Return array of names of block html elements +- [calculateBaseline](https://github.com/editor-js/utils/blob/main/packages/dom/src/calculateBaseline.ts) - Calculates the Y coordinate of the text baseline from the top of the element's margin box, +- [canSetCaret](https://github.com/editor-js/utils/blob/main/packages/dom/src/canSetCaret.ts) - Checks if we can set caret +- [containsOnlyInlineElements](https://github.com/editor-js/utils/blob/main/packages/dom/src/containsOnlyInlineElements.ts) - Check if passed content includes only inline elements +- [findAllInputs](https://github.com/editor-js/utils/blob/main/packages/dom/src/findAllInputs.ts) - Find all contenteditable, textarea and editable input elements passed holder contains +- [fragmentToString](https://github.com/editor-js/utils/blob/main/packages/dom/src/fragmentToString.ts) - Returns the HTML content of passed Document Fragment +- [getContentLength](https://github.com/editor-js/utils/blob/main/packages/dom/src/getContentLength.ts) - Return length of node`s text content +- [getDeepestBlockElements](https://github.com/editor-js/utils/blob/main/packages/dom/src/getDeepestBlockElements.ts) - Find and return all block elements in the passed parent (including subtree) +- [getDeepestNode](https://github.com/editor-js/utils/blob/main/packages/dom/src/getDeepestNode.ts) - Search for deepest node which is Leaf. +- [isCollapsedWhitespaces](https://github.com/editor-js/utils/blob/main/packages/dom/src/isCollapsedWhitespaces.ts) - Determine whether a passed text content is a collapsed whitespace. +- [isContentEditable](https://github.com/editor-js/utils/blob/main/packages/dom/src/isContentEditable.ts) - Check if passed element is contenteditable +- [isElement](https://github.com/editor-js/utils/blob/main/packages/dom/src/isElement.ts) - Check if object is DOM node +- [isEmpty](https://github.com/editor-js/utils/blob/main/packages/dom/src/isEmpty.ts) - breadth-first search (BFS) +- [isFragment](https://github.com/editor-js/utils/blob/main/packages/dom/src/isFragment.ts) - Check if object is DocumentFragment node +- [isHTMLString](https://github.com/editor-js/utils/blob/main/packages/dom/src/isHtmlString.ts) - Check if string contains html elements +- [isLeaf](https://github.com/editor-js/utils/blob/main/packages/dom/src/isLeaf.ts) - checks node if it is doesn't have any child nodes +- [isLineBreakTag](https://github.com/editor-js/utils/blob/main/packages/dom/src/isLineBreakTag.ts) - Check if element is BR or WBR +- [isNativeInput](https://github.com/editor-js/utils/blob/main/packages/dom/src/isNativeInput.ts) - Checks target if it is native input +- [isNodeEmpty](https://github.com/editor-js/utils/blob/main/packages/dom/src/isNodeEmpty.ts) - Checks node if it is empty +- [isSingleTag](https://github.com/editor-js/utils/blob/main/packages/dom/src/isSingleTag.ts) - Check if passed tag has no closed tag +- [make](https://github.com/editor-js/utils/blob/main/packages/dom/src/make.ts) - Helper for making Elements with class name and attributes +- [offset](https://github.com/editor-js/utils/blob/main/packages/dom/src/offset.ts) - Return element's offset related to the document +- [prepend](https://github.com/editor-js/utils/blob/main/packages/dom/src/prepend.ts) - Append element or a couple to the beginning of the parent elements +# About CodeX + + + CodeX is a team of digital specialists around the world interested in building high-quality open source products on a global market. We are [open](https://codex.so/join) for young people who want to constantly improve their skills and grow professionally with experiments in cutting-edge technologies. + + | 🌐 | Join 👋 | Twitter | Instagram | + | -- | -- | -- | -- | + | [codex.so](https://codex.so) | [codex.so/join](https://codex.so/join) |[@codex_team](http://twitter.com/codex_team) | [@codex_team](http://instagram.com/codex_team/) | \ No newline at end of file diff --git a/packages/dom/package.json b/packages/dom/package.json index cf5d1f3..f3a6cc0 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,7 @@ { "name": "@editorjs/dom", - "version": "0.0.1", + "description": "Utils useful for work with dom for Editor.js tools development", + "version": "0.0.2", "main": "dist/index.js", "license": "MIT", "scripts": { diff --git a/packages/dom/src/allInputsSelector.ts b/packages/dom/src/allInputsSelector.ts new file mode 100644 index 0000000..a128b57 --- /dev/null +++ b/packages/dom/src/allInputsSelector.ts @@ -0,0 +1,9 @@ +/** + * Returns CSS selector for all text inputs + */ +export function allInputsSelector(): string { + const allowedInputTypes = ['text', 'password', 'email', 'number', 'search', 'tel', 'url']; + + return '[contenteditable=true], textarea, input:not([type]), ' + + allowedInputTypes.map(type => `input[type="${type}"]`).join(', '); +} diff --git a/packages/dom/src/canSetCaret.ts b/packages/dom/src/canSetCaret.ts index 4ad4ab1..c972fc5 100644 --- a/packages/dom/src/canSetCaret.ts +++ b/packages/dom/src/canSetCaret.ts @@ -1,4 +1,4 @@ -import { isNativeInput } from './inputs'; +import { isNativeInput } from './isNativeInput'; import { isContentEditable } from './isContentEditable'; /** diff --git a/packages/dom/src/findAllInputs.ts b/packages/dom/src/findAllInputs.ts new file mode 100644 index 0000000..032027b --- /dev/null +++ b/packages/dom/src/findAllInputs.ts @@ -0,0 +1,24 @@ +import { containsOnlyInlineElements } from './containsOnlyInlineElements'; +import { getDeepestBlockElements } from './getDeepestBlockElements'; +import { allInputsSelector } from './allInputsSelector'; +import { isNativeInput } from './isNativeInput'; + +/** + * Find all contenteditable, textarea and editable input elements passed holder contains + * @param holder - element where to find inputs + * @returns - all inputs of the holder element + */ +export function findAllInputs(holder: HTMLElement): HTMLElement[] { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + return Array.from(holder.querySelectorAll(allInputsSelector()) as NodeListOf) + /** + * If contenteditable element contains block elements, treat them as inputs. + */ + .reduce((result, input) => { + if (isNativeInput(input) || containsOnlyInlineElements(input)) { + return [...result, input]; + } + + return [...result, ...getDeepestBlockElements(input)] as HTMLElement[]; + }, []); +} diff --git a/packages/dom/src/fragmentToString.ts b/packages/dom/src/fragmentToString.ts new file mode 100644 index 0000000..be2432e --- /dev/null +++ b/packages/dom/src/fragmentToString.ts @@ -0,0 +1,14 @@ +import { make } from './make'; + +/** + * Returns the HTML content of passed Document Fragment + * @param fragment - document fragment to process + * @returns the HTML content of passed Document Fragment + */ +export function fragmentToString(fragment: DocumentFragment): string { + const div = make('div'); + + div.appendChild(fragment); + + return div.innerHTML; +} diff --git a/packages/dom/src/getContentLength.ts b/packages/dom/src/getContentLength.ts index 8795f58..85fed94 100644 --- a/packages/dom/src/getContentLength.ts +++ b/packages/dom/src/getContentLength.ts @@ -1,4 +1,4 @@ -import { isNativeInput } from './inputs'; +import { isNativeInput } from './isNativeInput'; /** * Return length of node`s text content diff --git a/packages/dom/src/getDeepestNode.ts b/packages/dom/src/getDeepestNode.ts index d957eb8..9afc2e3 100644 --- a/packages/dom/src/getDeepestNode.ts +++ b/packages/dom/src/getDeepestNode.ts @@ -1,5 +1,6 @@ -import { isNativeInput } from './inputs'; -import { isLineBreakTag, isSingleTag } from './isTag'; +import { isNativeInput } from './isNativeInput'; +import { isLineBreakTag } from './isLineBreakTag'; +import { isSingleTag } from './isSingleTag'; /** * Search for deepest node which is Leaf. diff --git a/packages/dom/src/index.ts b/packages/dom/src/index.ts index b462334..c6f28d7 100644 --- a/packages/dom/src/index.ts +++ b/packages/dom/src/index.ts @@ -1,13 +1,15 @@ +import { allInputsSelector } from './allInputsSelector'; +import { isNativeInput } from './isNativeInput'; import { append } from './append'; import { blockElements } from './blockElements'; import { calculateBaseline } from './calculateBaseline'; import { canSetCaret } from './canSetCaret'; -import { checkContenteditableSliceForEmptiness } from './checkContenteditableSliceForEmptiness'; import { containsOnlyInlineElements } from './containsOnlyInlineElements'; +import { fragmentToString } from './fragmentToString'; import { getContentLength } from './getContentLength'; import { getDeepestBlockElements } from './getDeepestBlockElements'; import { getDeepestNode } from './getDeepestNode'; -import { allInputsSelector, isNativeInput, findAllInputs } from './inputs'; +import { findAllInputs } from './findAllInputs'; import { isCollapsedWhitespaces } from './isCollapsedWhitespaces'; import { isContentEditable } from './isContentEditable'; import { isElement } from './isElement'; @@ -16,7 +18,8 @@ import { isFragment } from './isFragment'; import { isHTMLString } from './isHtmlString'; import { isLeaf } from './isLeaf'; import { isNodeEmpty } from './isNodeEmpty'; -import { isSingleTag, isLineBreakTag } from './isTag'; +import { isLineBreakTag } from './isLineBreakTag'; +import { isSingleTag } from './isSingleTag'; import { make } from './make'; import { offset } from './offset'; import { prepend } from './prepend'; @@ -25,8 +28,8 @@ export { append, blockElements, calculateBaseline, canSetCaret, - checkContenteditableSliceForEmptiness, containsOnlyInlineElements, + fragmentToString, getContentLength, getDeepestBlockElements, getDeepestNode, diff --git a/packages/dom/src/inputs.ts b/packages/dom/src/inputs.ts deleted file mode 100644 index 5da2398..0000000 --- a/packages/dom/src/inputs.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { containsOnlyInlineElements } from './containsOnlyInlineElements'; -import { getDeepestBlockElements } from './getDeepestBlockElements'; - -/** - * Returns CSS selector for all text inputs - */ -export function allInputsSelector(): string { - const allowedInputTypes = ['text', 'password', 'email', 'number', 'search', 'tel', 'url']; - - return '[contenteditable=true], textarea, input:not([type]), ' - + allowedInputTypes.map(type => `input[type="${type}"]`).join(', '); -} - -/** - * Checks target if it is native input - * @param target - HTML element or string - * @returns true if target is an input element, false otherwise - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function isNativeInput(target: any): target is HTMLInputElement | HTMLTextAreaElement { - const nativeInputs = [ - 'INPUT', - 'TEXTAREA', - ]; - - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument - return target && target.tagName ? nativeInputs.includes(target.tagName) : false; -} - -/** - * Find all contenteditable, textarea and editable input elements passed holder contains - * @param holder - element where to find inputs - * @returns - all inputs of the holder element - */ -export function findAllInputs(holder: HTMLElement): HTMLElement[] { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - return Array.from(holder.querySelectorAll(allInputsSelector()) as NodeListOf) - /** - * If contenteditable element contains block elements, treat them as inputs. - */ - .reduce((result, input) => { - if (isNativeInput(input) || containsOnlyInlineElements(input)) { - return [...result, input]; - } - - return [...result, ...getDeepestBlockElements(input)] as HTMLElement[]; - }, []); -} diff --git a/packages/dom/src/isLineBreakTag.ts b/packages/dom/src/isLineBreakTag.ts new file mode 100644 index 0000000..cd7bf4d --- /dev/null +++ b/packages/dom/src/isLineBreakTag.ts @@ -0,0 +1,11 @@ +/** + * Check if element is BR or WBR + * @param element - element to check + * @returns boolean that represents if element is a line break tag + */ +export function isLineBreakTag(element: HTMLElement): element is HTMLBRElement { + return [ + 'BR', + 'WBR', + ].includes(element.tagName); +} diff --git a/packages/dom/src/isNativeInput.ts b/packages/dom/src/isNativeInput.ts new file mode 100644 index 0000000..b232742 --- /dev/null +++ b/packages/dom/src/isNativeInput.ts @@ -0,0 +1,15 @@ +/** + * Checks target if it is native input + * @param target - HTML element or string + * @returns true if target is an input element, false otherwise + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isNativeInput(target: any): target is HTMLInputElement | HTMLTextAreaElement { + const nativeInputs = [ + 'INPUT', + 'TEXTAREA', + ]; + + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument + return target && target.tagName ? nativeInputs.includes(target.tagName) : false; +} diff --git a/packages/dom/src/isNodeEmpty.ts b/packages/dom/src/isNodeEmpty.ts index 098a196..0344fc4 100644 --- a/packages/dom/src/isNodeEmpty.ts +++ b/packages/dom/src/isNodeEmpty.ts @@ -1,6 +1,7 @@ -import { isSingleTag, isLineBreakTag } from './isTag'; +import { isLineBreakTag } from './isLineBreakTag'; import { isElement } from './isElement'; -import { isNativeInput } from './inputs'; +import { isNativeInput } from './isNativeInput'; +import { isSingleTag } from './isSingleTag'; /** * Checks node if it is empty diff --git a/packages/dom/src/isTag.ts b/packages/dom/src/isSingleTag.ts similarity index 60% rename from packages/dom/src/isTag.ts rename to packages/dom/src/isSingleTag.ts index 313d78e..3f70f6d 100644 --- a/packages/dom/src/isTag.ts +++ b/packages/dom/src/isSingleTag.ts @@ -23,15 +23,3 @@ export function isSingleTag(tag: HTMLElement): boolean { 'WBR', ].includes(tag.tagName); } - -/** - * Check if element is BR or WBR - * @param element - element to check - * @returns boolean that represents if element is a line break tag - */ -export function isLineBreakTag(element: HTMLElement): element is HTMLBRElement { - return [ - 'BR', - 'WBR', - ].includes(element.tagName); -} diff --git a/packages/dom/tsconfig.json b/packages/dom/tsconfig.json index 1c9b4e9..7dcaf8b 100644 --- a/packages/dom/tsconfig.json +++ b/packages/dom/tsconfig.json @@ -1,5 +1,4 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", "rootDir": "src", diff --git a/packages/helpers/README.md b/packages/helpers/README.md new file mode 100644 index 0000000..95bae10 --- /dev/null +++ b/packages/helpers/README.md @@ -0,0 +1,38 @@ +# @editorjs/helpers +Utils useful for Editor.js tools development +### Installation + ``` + npm install @editorjs/helpers +``` +### Function list +- [beautifyShortcut](https://github.com/editor-js/utils/blob/main/packages/helpers/src/beautifyShortcut.ts) - Make shortcut command more human-readable +- [cacheable](https://github.com/editor-js/utils/blob/main/packages/helpers/src/cacheable.ts) - Decorator which provides ability to cache method or accessor result +- [capitalize](https://github.com/editor-js/utils/blob/main/packages/helpers/src/capitalize.ts) - Capitalizes first letter of the string +- [copyTextToClipboard](https://github.com/editor-js/utils/blob/main/packages/helpers/src/copyTextToClipboard.ts) - Copies passed text to the clipboard +- [debounce](https://github.com/editor-js/utils/blob/main/packages/helpers/src/debounce.ts) - Debouncing method +- [deepMerge](https://github.com/editor-js/utils/blob/main/packages/helpers/src/deepMerge.ts) - Merge two objects recursively +- [deprecationAssert](https://github.com/editor-js/utils/blob/main/packages/helpers/src/deprecationAssert.ts) - Common method for printing a warning about the usage of deprecated property or method. +- [notEmpty](https://github.com/editor-js/utils/blob/main/packages/helpers/src/empty.ts) - True if passed variable is not null/undefined/''/{} +- [isEmpty](https://github.com/editor-js/utils/blob/main/packages/helpers/src/empty.ts) - True if passed variable is null/undefined/''/{} +- [getValidUrl](https://github.com/editor-js/utils/blob/main/packages/helpers/src/getValidUrl.ts) - Returns valid URL. If it is going outside and valid, it returns itself +- [isPrintableKey](https://github.com/editor-js/utils/blob/main/packages/helpers/src/isPrintableKey.ts) - Returns true if passed key code is printable (a-Z, 0-9, etc) character. +- [throttle](https://github.com/editor-js/utils/blob/main/packages/helpers/src/throttle.ts) - Returns a function, that, when invoked, will only be triggered at most once during a given window of time. +- [typeOf](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Return string representation of the object type +- [isFunction](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Check if passed variable is a function +- [isObject](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Checks if passed argument is an object +- [isString](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Checks if passed argument is a string +- [isBoolean](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Checks if passed argument is boolean +- [isNumber](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Checks if passed argument is number +- [isUndefined](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Checks if passed argument is undefined +- [isClass](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Check if passed function is a class +- [isPromise](https://github.com/editor-js/utils/blob/main/packages/helpers/src/typeOf.ts) - Check if passed object is a Promise +- [getUserOS](https://github.com/editor-js/utils/blob/main/packages/helpers/src/userOS.ts) - Returns object with os name as key and boolean as value. Shows current user OS +- [equals](https://github.com/editor-js/utils/blob/main/packages/helpers/src/userOS.ts) - Compares two values with unknown type +# About CodeX + + + CodeX is a team of digital specialists around the world interested in building high-quality open source products on a global market. We are [open](https://codex.so/join) for young people who want to constantly improve their skills and grow professionally with experiments in cutting-edge technologies. + + | 🌐 | Join 👋 | Twitter | Instagram | + | -- | -- | -- | -- | + | [codex.so](https://codex.so) | [codex.so/join](https://codex.so/join) |[@codex_team](http://twitter.com/codex_team) | [@codex_team](http://instagram.com/codex_team/) | \ No newline at end of file diff --git a/packages/helpers/package.json b/packages/helpers/package.json index 5e0f05e..b8fb0dc 100644 --- a/packages/helpers/package.json +++ b/packages/helpers/package.json @@ -1,6 +1,7 @@ { "name": "@editorjs/helpers", - "version": "0.0.1", + "description": "Utils useful for Editor.js tools development", + "version": "0.0.2", "main": "dist/index.js", "license": "MIT", "scripts": { diff --git a/packages/helpers/tsconfig.json b/packages/helpers/tsconfig.json index 1c9b4e9..7dcaf8b 100644 --- a/packages/helpers/tsconfig.json +++ b/packages/helpers/tsconfig.json @@ -1,5 +1,4 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", "rootDir": "src", diff --git a/packages/keyboard/README.md b/packages/keyboard/README.md new file mode 100644 index 0000000..c7676cf --- /dev/null +++ b/packages/keyboard/README.md @@ -0,0 +1,16 @@ +# @editorjs/keyboard +Utils useful for work with keyboard for Editor.js tools development +### Installation + ``` + npm install @editorjs/keyboard +``` +### Function list +- [getKeyboardKeyForCode](https://github.com/editor-js/utils/blob/main/packages/keyboard/src/getKeyboardKeyForCode.ts) - Returns real layout-related keyboard key for a given key code. +# About CodeX + + + CodeX is a team of digital specialists around the world interested in building high-quality open source products on a global market. We are [open](https://codex.so/join) for young people who want to constantly improve their skills and grow professionally with experiments in cutting-edge technologies. + + | 🌐 | Join 👋 | Twitter | Instagram | + | -- | -- | -- | -- | + | [codex.so](https://codex.so) | [codex.so/join](https://codex.so/join) |[@codex_team](http://twitter.com/codex_team) | [@codex_team](http://instagram.com/codex_team/) | \ No newline at end of file diff --git a/packages/keyboard/package.json b/packages/keyboard/package.json index 61c96bc..cd09a6b 100644 --- a/packages/keyboard/package.json +++ b/packages/keyboard/package.json @@ -1,6 +1,7 @@ { "name": "@editorjs/keyboard", - "version": "0.0.1", + "description": "Utils useful for work with keyboard for Editor.js tools development", + "version": "0.0.2", "main": "dist/index.js", "license": "MIT", "scripts": { diff --git a/packages/keyboard/src/getKeyboardKeyForCode.ts b/packages/keyboard/src/getKeyboardKeyForCode.ts new file mode 100644 index 0000000..f862f11 --- /dev/null +++ b/packages/keyboard/src/getKeyboardKeyForCode.ts @@ -0,0 +1,101 @@ +declare global { + /** + * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardLayoutMap + */ + interface KeyboardLayoutMap { + /** + * Returns the element with the given key from the KeyboardLayoutMap object. + * @param key - key which is used for getting keyboard layout map + */ + get(key: string): string | undefined; + + /** + * method of the KeyboardLayoutMap interface returns a boolean indicating + * whether the object has an element with the specified key + * @param key - key which is used for gettings element + */ + has(key: string): boolean; + + /** + * The size read-only property of the KeyboardLayoutMap interface returns the number of elements in the map + */ + size: number; + + /** + * Method of the KeyboardLayoutMap interface returns a new Iterator object + * that contains the key/value pairs, in the same order as that provided by a for...in loop + * (the difference being that a for-in loop enumerates properties in the prototype chain as well) + */ + entries(): IterableIterator<[string, string]>; + + /** + * method of the KeyboardLayoutMap interface returns a new Iterator object + * that contains the keys for each index in the KeyboardLayoutMap object + */ + keys(): IterableIterator; + + /** + * method of the KeyboardLayoutMap interface returns a new Iterator object + * that contains the values for each index in the KeyboardLayoutMap object + */ + values(): IterableIterator; + + /** + * Executes a provided function once for each element of KeyboardLayoutMap. + * @param callbackfn + * @param thisArg + */ + forEach(callbackfn: (value: string, key: string, map: KeyboardLayoutMap) => void, thisArg?: unknown): void; + } + + /** + * The getLayoutMap() method of the Keyboard interface returns a Promise + * that resolves with an instance of KeyboardLayoutMap which is a map-like object + * with functions for retrieving the strings associated with specific physical keys. + * https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/getLayoutMap + */ + interface Keyboard { + /** + * Method that returns keyboard layout map with functoins + */ + getLayoutMap(): Promise; + } + /** + * Navigator interface + */ + interface Navigator { + /** + * Keyboard API. Not supported by Firefox and Safari. + */ + keyboard?: Keyboard; + } +} + +/** + * Returns real layout-related keyboard key for a given key code. + * For example, for "Slash" it will return "/" on US keyboard and "-" on Spanish keyboard. + * + * Works with Keyboard API which is not supported by Firefox and Safari. So fallback is used for these browsers. + * @see https://developer.mozilla.org/en-US/docs/Web/API/Keyboard + * @param code - {@link https://www.w3.org/TR/uievents-code/#key-alphanumeric-writing-system} + * @param fallback - fallback value to be returned if Keyboard API is not supported (Safari, Firefox) + */ +export async function getKeyboardKeyForCode(code: string, fallback: string): Promise { + const keyboard = navigator.keyboard; + + if (keyboard === null) { + return fallback; + } + + try { + const map = await keyboard.getLayoutMap(); + + const key = map.get(code); + + return key ?? fallback; + } catch (e) { + console.error(e); + + return fallback; + } +} diff --git a/packages/keyboard/src/index.ts b/packages/keyboard/src/index.ts index 1b3d52f..57983d5 100644 --- a/packages/keyboard/src/index.ts +++ b/packages/keyboard/src/index.ts @@ -1,94 +1,3 @@ -declare global { - /** - * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardLayoutMap - */ - interface KeyboardLayoutMap { - /** - * Returns the element with the given key from the KeyboardLayoutMap object. - * @param key - key which is used for getting keyboard layout map - */ - get(key: string): string | undefined; +import { getKeyboardKeyForCode } from './getKeyboardKeyForCode'; - /** - * method of the KeyboardLayoutMap interface returns a boolean indicating - * whether the object has an element with the specified key - * @param key - key which is used for gettings element - */ - has(key: string): boolean; - - /** - * The size read-only property of the KeyboardLayoutMap interface returns the number of elements in the map - */ - size: number; - - /** - * Method of the KeyboardLayoutMap interface returns a new Iterator object - * that contains the key/value pairs, in the same order as that provided by a for...in loop - * (the difference being that a for-in loop enumerates properties in the prototype chain as well) - */ - entries(): IterableIterator<[string, string]>; - - /** - * method of the KeyboardLayoutMap interface returns a new Iterator object - * that contains the keys for each index in the KeyboardLayoutMap object - */ - keys(): IterableIterator; - - /** - * method of the KeyboardLayoutMap interface returns a new Iterator object - * that contains the values for each index in the KeyboardLayoutMap object - */ - values(): IterableIterator; - - /** - * Executes a provided function once for each element of KeyboardLayoutMap. - * @param callbackfn - * @param thisArg - */ - forEach(callbackfn: (value: string, key: string, map: KeyboardLayoutMap) => void, thisArg?: unknown): void; - } - - /** - * The getLayoutMap() method of the Keyboard interface returns a Promise - * that resolves with an instance of KeyboardLayoutMap which is a map-like object - * with functions for retrieving the strings associated with specific physical keys. - * https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/getLayoutMap - */ - interface Keyboard { - /** - * Method that returns keyboard layout map with functoins - */ - getLayoutMap(): Promise; - } - /** - * Navigator interface - */ - interface Navigator { - /** - * Keyboard API. Not supported by Firefox and Safari. - */ - keyboard?: Keyboard; - } -} - -/** - * Returns real layout-related keyboard key for a given key code. - * For example, for "Slash" it will return "/" on US keyboard and "-" on Spanish keyboard. - * - * Works with Keyboard API which is not supported by Firefox and Safari. So fallback is used for these browsers. - * @see https://developer.mozilla.org/en-US/docs/Web/API/Keyboard - * @param code - {@link https://www.w3.org/TR/uievents-code/#key-alphanumeric-writing-system} - * @param fallback - fallback value to be returned if Keyboard API is not supported (Safari, Firefox) - */ -export async function getKeyboardKeyForCode(code: string, fallback: string): Promise { - const keyboard = navigator.keyboard; - - if (!keyboard) { - return fallback; - } - - const map = await keyboard.getLayoutMap(); - const key = map.get(code); - - return (key ?? '') || fallback; -} +export { getKeyboardKeyForCode }; diff --git a/packages/keyboard/tsconfig.json b/packages/keyboard/tsconfig.json index 43fd18c..00effdd 100644 --- a/packages/keyboard/tsconfig.json +++ b/packages/keyboard/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", "rootDir": "src", + "composite": true, }, "include": ["**/*"], "exclude": ["dist"] diff --git a/scripts/generateReadme.ts b/scripts/generateReadme.ts new file mode 100644 index 0000000..2459f94 --- /dev/null +++ b/scripts/generateReadme.ts @@ -0,0 +1,160 @@ +import * as fs from 'fs-extra'; +import * as path from 'path'; +import * as ts from 'typescript'; + +/** + * Parse the first line of JSDoc description from a method node + * @param node - TypeScript AST node + * @returns First line of JSDoc description string + */ +function parseJSDocDescription(node: ts.Node): string { + const jsDocs = ts.getJSDocCommentsAndTags(node); + + if (jsDocs.length > 0) { + const comment = jsDocs.find(doc => ts.isJSDoc(doc)); + + if (comment && ts.isJSDoc(comment)) { + const commentText = comment.comment; + + if (commentText !== undefined) { + const description = typeof commentText === 'string' ? commentText : commentText.map(c => c.text).join(' '); + const firstLine = description.split('\n')[0]; + + return firstLine; + } + } + } + + return ''; +} + +/** + * Extract method names, descriptions, and file paths from a TypeScript file + * @param filePath - Path to the TypeScript file + * @returns Array of strings with function name, description, and file path + */ +function extractMethodDescriptions(filePath: string): string[] { + const fileContent = fs.readFileSync(filePath, 'utf8'); + const sourceFile = ts.createSourceFile(filePath, fileContent, ts.ScriptTarget.Latest, true); + const descriptions: string[] = []; + const relativePath = path.relative(path.join(__dirname, '../packages'), filePath).replace(/\\/g, '/'); + + /** + * Visits each node in the AST and extracts method names, descriptions, and file paths + * @param node - The current TypeScript AST node + */ + function visit(node: ts.Node): void { + if (ts.isFunctionDeclaration(node) && node.name) { + const functionName = node.name.text; + const description = parseJSDocDescription(node); + + if (description) { + const githubUrl = `https://github.com/editor-js/utils/blob/main/packages/${relativePath}`; + + descriptions.push(`- [${functionName}](${githubUrl}) - ${description}`); + } + } + ts.forEachChild(node, visit); + } + + visit(sourceFile); + + return descriptions; +} + +/** + * Extract the description from package.json + * @param packageDir - Directory path where package.json is located + * @returns The description from package.json, or a default message if not found + */ +function extractPackageDescription(packageDir: string): string { + const packageJsonPath = path.join(packageDir, 'package.json'); + + // Check if package.json exists + if (!fs.existsSync(packageJsonPath)) { + console.error(`package.json not found in ${packageDir}`); + + return 'Description not available'; + } + + try { + // Read and parse package.json + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const packageJson = fs.readJSONSync(packageJsonPath); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return + return (Boolean(packageJson.description)) ? packageJson.description : 'Description not available'; + } catch (error) { + console.error(`Failed to read or parse ${packageJsonPath}:`, error); + + return 'Description not available'; + } +} + +/** + * Generate README.md documentation by parsing TypeScript files + * @param dirPath - Directory path + */ +function generateDocs(dirPath: string): void { + const packageName = path.basename(dirPath); + const srcPath = path.join(dirPath, 'src'); + const files = fs.readdirSync(srcPath).filter(file => file.endsWith('.ts') && file !== 'index.ts'); + const readmePath = path.join(dirPath, 'README.md'); + const docContent: string[] = [`# @editorjs/${packageName}`]; + const docFooter: string = '# About CodeX\n \ + \n\n \ + CodeX is a team of digital specialists around the world interested in building high-quality open source products on a global market. We are [open](https://codex.so/join) for young people who want to constantly improve their skills and grow professionally with experiments in cutting-edge technologies.\n\n\ + | 🌐 | Join 👋 | Twitter | Instagram |\n \ + | -- | -- | -- | -- | \n \ + | [codex.so](https://codex.so) | [codex.so/join](https://codex.so/join) |[@codex_team](http://twitter.com/codex_team) | [@codex_team](http://instagram.com/codex_team/) |'; + const description = extractPackageDescription(dirPath); + const packageInstall: string = `### Installation \n \ +\`\`\`\n \ + npm install @editorjs/${packageName}\n\ +\`\`\``; + + docContent.push(description); + docContent.push(packageInstall); + docContent.push('### Function list'); + + files.forEach((file) => { + const filePath = path.join(srcPath, file); + const descriptions = extractMethodDescriptions(filePath); + + if (descriptions.length > 0) { + docContent.push(...descriptions); + } + }); + + docContent.push(docFooter); + + /** + * Check that we have contents besides header and footer and installation and description of the package + */ + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + if (docContent.length > 5) { + fs.writeFileSync(readmePath, docContent.join('\n'), 'utf8'); + console.log(`Documentation generated in ${readmePath}`); + } else { + console.log(`No documentation found for ${dirPath}`); + } +} + +/** + * Generate README.md files for all packages + */ +function generateDocsForAllPackages(): void { + const packagesDir = path.resolve(__dirname, '../packages'); + const packages = fs.readdirSync(packagesDir); + + packages.forEach((pkg) => { + const pkgPath = path.join(packagesDir, pkg); + + if (fs.lstatSync(pkgPath).isDirectory()) { + generateDocs(pkgPath); + } + }); +} + +// Execute the script +generateDocsForAllPackages(); diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 0d12c16..cee72bf 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -3,6 +3,7 @@ "include": [ "packages/**/*.ts", "eslint.config.mjs", - "src/**/*.ts" + "src/**/*.ts", + "scripts/**/*.ts" ], } diff --git a/tsconfig.json b/tsconfig.json index 474c73d..ebb2e22 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,12 +24,12 @@ "include": ["src/**/*"], "exclude": [ "node_modules", - "packages/**/dist*" + "packages/**/dist*", ], "references": [ { "path": "packages/dom" }, { "path": "packages/caret" }, - { "path": "packages/keyboard" }, - { "path": "packages/helpers" } + { "path": "packages/helpers" }, + { "path": "packages/keyboard" } ] } diff --git a/yarn.lock b/yarn.lock index 53e402c..547d42a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,15 @@ __metadata: version: 8 cacheKey: 10c0 +"@cspotcode/source-map-support@npm:^0.8.0": + version: 0.8.1 + resolution: "@cspotcode/source-map-support@npm:0.8.1" + dependencies: + "@jridgewell/trace-mapping": "npm:0.3.9" + checksum: 10c0/05c5368c13b662ee4c122c7bfbe5dc0b613416672a829f3e78bc49a357a197e0218d6e74e7c66cfcd04e15a179acab080bd3c69658c9fbefd0e1ccd950a07fc6 + languageName: node + linkType: hard + "@editorjs/caret@workspace:packages/caret": version: 0.0.0-use.local resolution: "@editorjs/caret@workspace:packages/caret" @@ -37,9 +46,12 @@ __metadata: version: 0.0.0-use.local resolution: "@editorjs/utils@workspace:." dependencies: + "@types/fs-extra": "npm:^11" "@types/node": "npm:^20.10.7" eslint: "npm:^9.0.0" eslint-config-codex: "npm:^2.0.0" + fs-extra: "npm:^11.2.0" + ts-node: "npm:^10.9.2" typescript: "npm:^5.4.5" typescript-eslint: "npm:^7.9.0" languageName: unknown @@ -130,6 +142,30 @@ __metadata: languageName: node linkType: hard +"@jridgewell/resolve-uri@npm:^3.0.3": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:0.3.9": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.0.3" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + checksum: 10c0/fa425b606d7c7ee5bfa6a31a7b050dd5814b4082f318e0e4190f991902181b4330f43f4805db1dd4f2433fd0ed9cc7a7b9c2683f1deeab1df1b0a98b1e24055b + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -233,6 +269,34 @@ __metadata: languageName: node linkType: hard +"@tsconfig/node10@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node10@npm:1.0.11" + checksum: 10c0/28a0710e5d039e0de484bdf85fee883bfd3f6a8980601f4d44066b0a6bcd821d31c4e231d1117731c4e24268bd4cf2a788a6787c12fc7f8d11014c07d582783c + languageName: node + linkType: hard + +"@tsconfig/node12@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node12@npm:1.0.11" + checksum: 10c0/dddca2b553e2bee1308a056705103fc8304e42bb2d2cbd797b84403a223b25c78f2c683ec3e24a095e82cd435387c877239bffcb15a590ba817cd3f6b9a99fd9 + languageName: node + linkType: hard + +"@tsconfig/node14@npm:^1.0.0": + version: 1.0.3 + resolution: "@tsconfig/node14@npm:1.0.3" + checksum: 10c0/67c1316d065fdaa32525bc9449ff82c197c4c19092b9663b23213c8cbbf8d88b6ed6a17898e0cbc2711950fbfaf40388938c1c748a2ee89f7234fc9e7fe2bf44 + languageName: node + linkType: hard + +"@tsconfig/node16@npm:^1.0.2": + version: 1.0.4 + resolution: "@tsconfig/node16@npm:1.0.4" + checksum: 10c0/05f8f2734e266fb1839eb1d57290df1664fe2aa3b0fdd685a9035806daa635f7519bf6d5d9b33f6e69dd545b8c46bd6e2b5c79acb2b1f146e885f7f11a42a5bb + languageName: node + linkType: hard + "@types/eslint@npm:^8.56.10": version: 8.56.11 resolution: "@types/eslint@npm:8.56.11" @@ -250,6 +314,16 @@ __metadata: languageName: node linkType: hard +"@types/fs-extra@npm:^11": + version: 11.0.4 + resolution: "@types/fs-extra@npm:11.0.4" + dependencies: + "@types/jsonfile": "npm:*" + "@types/node": "npm:*" + checksum: 10c0/9e34f9b24ea464f3c0b18c3f8a82aefc36dc524cc720fc2b886e5465abc66486ff4e439ea3fb2c0acebf91f6d3f74e514f9983b1f02d4243706bdbb7511796ad + languageName: node + linkType: hard + "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" @@ -264,6 +338,24 @@ __metadata: languageName: node linkType: hard +"@types/jsonfile@npm:*": + version: 6.1.4 + resolution: "@types/jsonfile@npm:6.1.4" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/b12d068b021e4078f6ac4441353965769be87acf15326173e2aea9f3bf8ead41bd0ad29421df5bbeb0123ec3fc02eb0a734481d52903704a1454a1845896b9eb + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 22.3.0 + resolution: "@types/node@npm:22.3.0" + dependencies: + undici-types: "npm:~6.18.2" + checksum: 10c0/855be3b97f4262a84818f889ff898e147dcef4f72b866e3551a8367380cdb63a45cf3929f09d9a0647f62706f8d4772e91a1ecd1bd7c6a80d6744c2b0cbca608 + languageName: node + linkType: hard + "@types/node@npm:^20.10.7": version: 20.14.15 resolution: "@types/node@npm:20.14.15" @@ -470,7 +562,16 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.11.3, acorn@npm:^8.12.0, acorn@npm:^8.9.0": +"acorn-walk@npm:^8.1.1": + version: 8.3.3 + resolution: "acorn-walk@npm:8.3.3" + dependencies: + acorn: "npm:^8.11.0" + checksum: 10c0/4a9e24313e6a0a7b389e712ba69b66b455b4cb25988903506a8d247e7b126f02060b05a8a5b738a9284214e4ca95f383dd93443a4ba84f1af9b528305c7f243b + languageName: node + linkType: hard + +"acorn@npm:^8.11.0, acorn@npm:^8.11.3, acorn@npm:^8.12.0, acorn@npm:^8.4.1, acorn@npm:^8.9.0": version: 8.12.1 resolution: "acorn@npm:8.12.1" bin: @@ -514,6 +615,13 @@ __metadata: languageName: node linkType: hard +"arg@npm:^4.1.0": + version: 4.1.3 + resolution: "arg@npm:4.1.3" + checksum: 10c0/070ff801a9d236a6caa647507bdcc7034530604844d64408149a26b9e87c2f97650055c0f049abd1efc024b334635c01f29e0b632b371ac3f26130f4cf65997a + languageName: node + linkType: hard + "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -717,6 +825,13 @@ __metadata: languageName: node linkType: hard +"create-require@npm:^1.1.0": + version: 1.1.1 + resolution: "create-require@npm:1.1.1" + checksum: 10c0/157cbc59b2430ae9a90034a5f3a1b398b6738bf510f713edc4d4e45e169bc514d3d99dd34d8d01ca7ae7830b5b8b537e46ae8f3c8f932371b0875c0151d7ec91 + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.2": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -820,6 +935,13 @@ __metadata: languageName: node linkType: hard +"diff@npm:^4.0.1": + version: 4.0.2 + resolution: "diff@npm:4.0.2" + checksum: 10c0/81b91f9d39c4eaca068eb0c1eb0e4afbdc5bb2941d197f513dd596b820b956fef43485876226d65d497bebc15666aa2aa82c679e84f65d5f2bfbf14ee46e32c1 + languageName: node + linkType: hard + "dir-glob@npm:^3.0.1": version: 3.0.1 resolution: "dir-glob@npm:3.0.1" @@ -1417,6 +1539,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.2.0": + version: 11.2.0 + resolution: "fs-extra@npm:11.2.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/d77a9a9efe60532d2e790e938c81a02c1b24904ef7a3efb3990b835514465ba720e99a6ea56fd5e2db53b4695319b644d76d5a0e9988a2beef80aa7b1da63398 + languageName: node + linkType: hard + "function-bind@npm:^1.1.2": version: 1.1.2 resolution: "function-bind@npm:1.1.2" @@ -1550,7 +1683,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.2.4": +"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -1882,6 +2015,19 @@ __metadata: languageName: node linkType: hard +"jsonfile@npm:^6.0.1": + version: 6.1.0 + resolution: "jsonfile@npm:6.1.0" + dependencies: + graceful-fs: "npm:^4.1.6" + universalify: "npm:^2.0.0" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10c0/4f95b5e8a5622b1e9e8f33c96b7ef3158122f595998114d1e7f03985649ea99cb3cd99ce1ed1831ae94c8c8543ab45ebd044207612f31a56fd08462140e46865 + languageName: node + linkType: hard + "keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -1924,6 +2070,13 @@ __metadata: languageName: node linkType: hard +"make-error@npm:^1.1.1": + version: 1.3.6 + resolution: "make-error@npm:1.3.6" + checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f + languageName: node + linkType: hard + "merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" @@ -2526,6 +2679,44 @@ __metadata: languageName: node linkType: hard +"ts-node@npm:^10.9.2": + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" + dependencies: + "@cspotcode/source-map-support": "npm:^0.8.0" + "@tsconfig/node10": "npm:^1.0.7" + "@tsconfig/node12": "npm:^1.0.7" + "@tsconfig/node14": "npm:^1.0.0" + "@tsconfig/node16": "npm:^1.0.2" + acorn: "npm:^8.4.1" + acorn-walk: "npm:^8.1.1" + arg: "npm:^4.1.0" + create-require: "npm:^1.1.0" + diff: "npm:^4.0.1" + make-error: "npm:^1.1.1" + v8-compile-cache-lib: "npm:^3.0.1" + yn: "npm:3.1.1" + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + bin: + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-esm: dist/bin-esm.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: 10c0/5f29938489f96982a25ba650b64218e83a3357d76f7bede80195c65ab44ad279c8357264639b7abdd5d7e75fc269a83daa0e9c62fd8637a3def67254ecc9ddc2 + languageName: node + linkType: hard + "tsconfig-paths@npm:^3.15.0": version: 3.15.0 resolution: "tsconfig-paths@npm:3.15.0" @@ -2668,6 +2859,20 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~6.18.2": + version: 6.18.2 + resolution: "undici-types@npm:6.18.2" + checksum: 10c0/dea28163891a5af7624c120107dc07a74c369ee94c6dd1d0de29af061ee129fac4846f97130589f4436b85f6102c73d30328ca908be02626dd8ab9fec5642aba + languageName: node + linkType: hard + +"universalify@npm:^2.0.0": + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: 10c0/73e8ee3809041ca8b818efb141801a1004e3fc0002727f1531f4de613ea281b494a40909596dae4a042a4fb6cd385af5d4db2e137b1362e0e91384b828effd3a + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -2684,6 +2889,13 @@ __metadata: languageName: node linkType: hard +"v8-compile-cache-lib@npm:^3.0.1": + version: 3.0.1 + resolution: "v8-compile-cache-lib@npm:3.0.1" + checksum: 10c0/bdc36fb8095d3b41df197f5fb6f11e3a26adf4059df3213e3baa93810d8f0cc76f9a74aaefc18b73e91fe7e19154ed6f134eda6fded2e0f1c8d2272ed2d2d391 + languageName: node + linkType: hard + "vue-eslint-parser@npm:^9.4.2, vue-eslint-parser@npm:^9.4.3": version: 9.4.3 resolution: "vue-eslint-parser@npm:9.4.3" @@ -2752,6 +2964,13 @@ __metadata: languageName: node linkType: hard +"yn@npm:3.1.1": + version: 3.1.1 + resolution: "yn@npm:3.1.1" + checksum: 10c0/0732468dd7622ed8a274f640f191f3eaf1f39d5349a1b72836df484998d7d9807fbea094e2f5486d6b0cd2414aad5775972df0e68f8604db89a239f0f4bf7443 + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0"