From 0493f679a4b49045042c09785d4dbcb3e36f0953 Mon Sep 17 00:00:00 2001 From: Alex Yang <himself65@outlook.com> Date: Sun, 20 Oct 2024 20:07:48 -0700 Subject: [PATCH] fix(core): inline `python-format-js` (#1356) --- .changeset/metal-worms-decide.md | 5 + package.json | 3 - packages/core/package.json | 3 +- packages/core/src/prompts/base.ts | 2 +- packages/core/src/prompts/format.ts | 207 +++++++++++++++++++++++++++ patches/python-format-js@1.4.3.patch | 0 pnpm-lock.yaml | 13 -- 7 files changed, 214 insertions(+), 19 deletions(-) create mode 100644 .changeset/metal-worms-decide.md create mode 100644 packages/core/src/prompts/format.ts delete mode 100644 patches/python-format-js@1.4.3.patch diff --git a/.changeset/metal-worms-decide.md b/.changeset/metal-worms-decide.md new file mode 100644 index 000000000..4c60cd91a --- /dev/null +++ b/.changeset/metal-worms-decide.md @@ -0,0 +1,5 @@ +--- +"@llamaindex/core": patch +--- + +fix(core): inline `python-format-js` diff --git a/package.json b/package.json index ad275d09d..0b1ddfa4b 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,6 @@ "overrides": { "trim": "1.0.1", "protobufjs": "7.2.6" - }, - "patchedDependencies": { - "python-format-js@1.4.3": "patches/python-format-js@1.4.3.patch" } }, "lint-staged": { diff --git a/packages/core/package.json b/packages/core/package.json index d5113b004..994670235 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -336,8 +336,7 @@ "ajv": "^8.17.1", "bunchee": "5.5.1", "happy-dom": "^15.7.4", - "natural": "^8.0.1", - "python-format-js": "^1.4.3" + "natural": "^8.0.1" }, "dependencies": { "@llamaindex/env": "workspace:*", diff --git a/packages/core/src/prompts/base.ts b/packages/core/src/prompts/base.ts index 0ec65ba37..a4e83426e 100644 --- a/packages/core/src/prompts/base.ts +++ b/packages/core/src/prompts/base.ts @@ -1,7 +1,7 @@ -import format from "python-format-js"; import type { ChatMessage } from "../llms"; import type { BaseOutputParser, Metadata } from "../schema"; import { objectEntries } from "../utils"; +import { format } from "./format"; import { PromptType } from "./prompt-type"; type MappingFn<TemplatesVar extends string[] = string[]> = ( diff --git a/packages/core/src/prompts/format.ts b/packages/core/src/prompts/format.ts new file mode 100644 index 000000000..4fb875958 --- /dev/null +++ b/packages/core/src/prompts/format.ts @@ -0,0 +1,207 @@ +/** + * MIT License + * + * Copyright (c) 2019 jhonararipe + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +"use strict"; +function formatImpl(this: string, ...args_: any[]) { + // Create variables + let self = this; + const __patterns__ = self.match(/({.*?})/g); + const { + REF, + FILL_CHAR, + MASK_NUMBER, + ALIGN_OP, + CROP_SIZE, + DOT, + FRACTION, + TYPE_VAR, + } = { + REF: 1, + FILL_CHAR: 2, + MASK_NUMBER: 3, + ALIGN_OP: 4, + CROP_SIZE: 5, + DOT: 6, + FRACTION: 7, + TYPE_VAR: 8, + }; + const DEFAULT_PLACE = 6; + const ALL_REGEXP = + /{(\w+)?:([^>\^<\d#]|0)?([#%,])?([>^<\.])?(\d+)?(\.)?(\d+)?([eEfFgGdxXobn#%])?}/g; + const regExpBasic = /{\[?(\w+)\]?}/; // it's not best solution + const isObject = typeof args_[0] === "object"; + // types/use logic + __patterns__?.map((pattern, patt_index) => { + const kargs = ALL_REGEXP.exec(pattern) || ALL_REGEXP.exec(pattern); + const wargs = regExpBasic.exec(pattern); + + // Insert values (one 2 one / array / object) + const INDEX_VAR = + (wargs ? wargs[REF] : kargs ? kargs[REF] : patt_index) || patt_index; + // @ts-expect-error + const NATUAL_VALUE = isObject ? args_[0][INDEX_VAR] : args_[INDEX_VAR]; + // @ts-expect-error + let ACTUAL_VALUE = isObject ? args_[0][INDEX_VAR] : args_[INDEX_VAR]; + + // Verify sintax/semantic + if (ACTUAL_VALUE === null || ACTUAL_VALUE === undefined) + throw new Error( + `Replacement index ${INDEX_VAR} out of range for positional args tuple`, + ); + if (kargs) { + // If TYPE_VAR is not defined and the first argument is a number, pad a string should from left, so set TYPE_VAR to "d" + if (kargs[TYPE_VAR] === undefined && typeof ACTUAL_VALUE === "number") { + kargs[TYPE_VAR] = "d"; + } + const LETTER = + (!kargs[FILL_CHAR] + ? false + : !kargs[ALIGN_OP] && + [..."FfbefoxXn"].includes(kargs[FILL_CHAR].toLowerCase()) + ? kargs[FILL_CHAR] + : kargs[TYPE_VAR]) || kargs[TYPE_VAR]; + // padronaze + if (LETTER) { + const floatSize = pattern.includes(".") + ? Number(kargs[FRACTION] || kargs[CROP_SIZE]) + : DEFAULT_PLACE; + switch (LETTER) { + case "E": + ACTUAL_VALUE = + ACTUAL_VALUE.toExponential(DEFAULT_PLACE).toUpperCase(); + break; + case "e": + ACTUAL_VALUE = ACTUAL_VALUE.toExponential(DEFAULT_PLACE); + break; + case "X": + ACTUAL_VALUE = ACTUAL_VALUE.toString(16).toUpperCase(); + break; + case "x": + ACTUAL_VALUE = ACTUAL_VALUE.toString(16); // Hexadecimal + break; + case "b": + ACTUAL_VALUE = ACTUAL_VALUE.toString(2); // Binary + break; + case "f": + case "F": + ACTUAL_VALUE = ACTUAL_VALUE.toFixed(floatSize); + break; + case "o": + ACTUAL_VALUE = ACTUAL_VALUE.toString(8); // Octal + break; + default: + break; + } + // mask + switch (kargs[MASK_NUMBER]) { + case "#": + const MASK = { + x: "0x", + X: "0X", + o: "0o", + b: "0b", + }[LETTER]; + ACTUAL_VALUE = MASK + ACTUAL_VALUE; + break; + } + } + // signal + if ( + // @ts-expect-error + [..." +-,%"].includes(kargs[FILL_CHAR]) && + typeof NATUAL_VALUE === "number" + ) { + ACTUAL_VALUE = ACTUAL_VALUE.toString().replace("-", ""); + if (NATUAL_VALUE >= 0) + switch (kargs[FILL_CHAR]) { + case "+": + ACTUAL_VALUE = "+" + ACTUAL_VALUE; + break; + case " ": + ACTUAL_VALUE = " " + ACTUAL_VALUE; + break; + case ",": + ACTUAL_VALUE = NATUAL_VALUE.toString() + .split(/(?=(?:...)*$)/) + .join(kargs[FILL_CHAR]); + break; + case "%": + ACTUAL_VALUE = + (NATUAL_VALUE * 100).toFixed( + // @ts-expect-error + kargs[FRACTION] || DEFAULT_PLACE, + ) + "%"; + break; + } + else ACTUAL_VALUE = "-" + ACTUAL_VALUE; + } + // space / order / trim + if (kargs[CROP_SIZE]) { + ACTUAL_VALUE = ACTUAL_VALUE.toString(); + const FILL_ELEMENT = kargs[FILL_CHAR] || " "; + const SIZE_STRING = ACTUAL_VALUE.length; + const SIZE_ARG = kargs[CROP_SIZE]; + const FILL_LENGTH = SIZE_STRING > SIZE_ARG ? SIZE_STRING : SIZE_ARG; + const FILL = FILL_ELEMENT.repeat(FILL_LENGTH); + + switch (kargs[ALIGN_OP] || kargs[FILL_CHAR]) { + case "<": + ACTUAL_VALUE = ACTUAL_VALUE.padEnd(FILL_LENGTH, FILL_ELEMENT); + break; + case ".": + if (!(LETTER && /[fF]/.test(LETTER))) + ACTUAL_VALUE = ACTUAL_VALUE.slice(0, SIZE_ARG); + break; + case ">": + ACTUAL_VALUE = ACTUAL_VALUE.padStart(FILL_LENGTH, FILL_ELEMENT); + break; + case "^": + const length_start = Math.floor((FILL_LENGTH - SIZE_STRING) / 2); + const string_start = + length_start > 0 + ? FILL_ELEMENT.repeat(length_start) + ACTUAL_VALUE + : ACTUAL_VALUE; + + ACTUAL_VALUE = FILL.replace( + RegExp(`.{${string_start.length}}`), + string_start, + ); + break; + default: + ACTUAL_VALUE = LETTER + ? ACTUAL_VALUE.padStart(FILL_LENGTH, FILL_ELEMENT) + : ACTUAL_VALUE.padEnd(FILL_LENGTH, FILL_ELEMENT); + break; + } + } + } + + // SET Definitive value + self = self.replace(pattern, ACTUAL_VALUE); + }); + + return self; +} + +export const format = (inputString: string, ...param: any[]) => + formatImpl.apply(inputString, param); diff --git a/patches/python-format-js@1.4.3.patch b/patches/python-format-js@1.4.3.patch deleted file mode 100644 index e69de29bb..000000000 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cfcf56519..9fc77eefc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,11 +8,6 @@ overrides: trim: 1.0.1 protobufjs: 7.2.6 -patchedDependencies: - python-format-js@1.4.3: - hash: 2qoyzwmpaczaj2mabgmoz6ccpy - path: patches/python-format-js@1.4.3.patch - importers: .: @@ -420,9 +415,6 @@ importers: natural: specifier: ^8.0.1 version: 8.0.1(@aws-sdk/credential-providers@3.675.0) - python-format-js: - specifier: ^1.4.3 - version: 1.4.3(patch_hash=2qoyzwmpaczaj2mabgmoz6ccpy) packages/core/tests: devDependencies: @@ -10326,9 +10318,6 @@ packages: resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==} engines: {node: '>=12.20'} - python-format-js@1.4.3: - resolution: {integrity: sha512-0iK5zP5HMf4F3Xc3Uo6hggPu4ylEQCKNoLXUYe3S1YfYkFG6DxGDO3KozCrySntAZTPmP9yRI+eMq0MXweHqIw==} - qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} @@ -25286,8 +25275,6 @@ snapshots: dependencies: escape-goat: 4.0.0 - python-format-js@1.4.3(patch_hash=2qoyzwmpaczaj2mabgmoz6ccpy): {} - qs@6.11.0: dependencies: side-channel: 1.0.6 -- GitLab