更新开发文档和技能索引,优化角色驱动的技能使用规范。调整了各角色的主技能和辅助技能的描述,确保开发者在不同目录下遵循相应的开发风格和流程。增加了变更关联检查的要求,确保代码变更后进行必要的检查以防漏改。

This commit is contained in:
Alex-larget
2026-02-25 11:04:08 +08:00
parent 28deb34645
commit 8e4d61e22b
369 changed files with 91393 additions and 16 deletions

View File

@@ -0,0 +1,15 @@
/**
* Adapted from https://github.com/mysqljs/sqlstring/blob/cd528556b4b6bcf300c3db515026935dedf7cfa1/lib/SqlString.js
* MIT LICENSE: https://github.com/mysqljs/sqlstring/blob/cd528556b4b6bcf300c3db515026935dedf7cfa1/LICENSE
*/
import type { Raw, SqlValue, Timezone } from './types.js';
import { Buffer } from 'node:buffer';
export type { Raw, SqlValue, Timezone } from './types.js';
export declare const dateToString: (date: Date, timezone: Timezone) => string;
export declare const escapeId: (value: SqlValue, forbidQualified?: boolean) => string;
export declare const objectToValues: (object: Record<string, SqlValue>, timezone?: Timezone) => string;
export declare const bufferToString: (buffer: Buffer) => string;
export declare const arrayToList: (array: SqlValue[], timezone?: Timezone) => string;
export declare const escape: (value: SqlValue, stringifyObjects?: boolean, timezone?: Timezone) => string;
export declare const format: (sql: string, values?: SqlValue | SqlValue[], stringifyObjects?: boolean, timezone?: Timezone) => string;
export declare const raw: (sql: string) => Raw;

View File

@@ -0,0 +1,398 @@
"use strict";
/**
* Adapted from https://github.com/mysqljs/sqlstring/blob/cd528556b4b6bcf300c3db515026935dedf7cfa1/lib/SqlString.js
* MIT LICENSE: https://github.com/mysqljs/sqlstring/blob/cd528556b4b6bcf300c3db515026935dedf7cfa1/LICENSE
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.raw = exports.format = exports.escape = exports.arrayToList = exports.bufferToString = exports.objectToValues = exports.escapeId = exports.dateToString = void 0;
const node_buffer_1 = require("node:buffer");
const regex = {
backtick: /`/g,
dot: /\./g,
timezone: /([+\-\s])(\d\d):?(\d\d)?/,
escapeChars: /[\0\b\t\n\r\x1a"'\\]/g,
};
const CHARS_ESCAPE_MAP = {
'\0': '\\0',
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\r': '\\r',
'\x1a': '\\Z',
'"': '\\"',
"'": "\\'",
'\\': '\\\\',
};
const charCode = {
singleQuote: 39,
backtick: 96,
backslash: 92,
dash: 45,
slash: 47,
asterisk: 42,
questionMark: 63,
newline: 10,
space: 32,
tab: 9,
carriageReturn: 13,
};
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
const isWordChar = (code) => (code >= 65 && code <= 90) ||
(code >= 97 && code <= 122) ||
(code >= 48 && code <= 57) ||
code === 95;
const isWhitespace = (code) => code === charCode.space ||
code === charCode.tab ||
code === charCode.newline ||
code === charCode.carriageReturn;
const hasOnlyWhitespaceBetween = (sql, start, end) => {
if (start >= end)
return true;
for (let i = start; i < end; i++) {
const code = sql.charCodeAt(i);
if (code !== charCode.space &&
code !== charCode.tab &&
code !== charCode.newline &&
code !== charCode.carriageReturn)
return false;
}
return true;
};
const toLower = (code) => code | 32;
const matchesWord = (sql, position, word, length) => {
for (let offset = 0; offset < word.length; offset++)
if (toLower(sql.charCodeAt(position + offset)) !== word.charCodeAt(offset))
return false;
return ((position === 0 || !isWordChar(sql.charCodeAt(position - 1))) &&
(position + word.length >= length ||
!isWordChar(sql.charCodeAt(position + word.length))));
};
const skipSqlContext = (sql, position) => {
const currentChar = sql.charCodeAt(position);
const nextChar = sql.charCodeAt(position + 1);
if (currentChar === charCode.singleQuote) {
for (let cursor = position + 1; cursor < sql.length; cursor++) {
if (sql.charCodeAt(cursor) === charCode.backslash)
cursor++;
else if (sql.charCodeAt(cursor) === charCode.singleQuote)
return cursor + 1;
}
return sql.length;
}
if (currentChar === charCode.backtick) {
const length = sql.length;
for (let cursor = position + 1; cursor < length; cursor++) {
if (sql.charCodeAt(cursor) !== charCode.backtick)
continue;
if (sql.charCodeAt(cursor + 1) === charCode.backtick) {
cursor++;
continue;
}
return cursor + 1;
}
return length;
}
if (currentChar === charCode.dash && nextChar === charCode.dash) {
const lineBreak = sql.indexOf('\n', position + 2);
return lineBreak === -1 ? sql.length : lineBreak + 1;
}
if (currentChar === charCode.slash && nextChar === charCode.asterisk) {
const commentEnd = sql.indexOf('*/', position + 2);
return commentEnd === -1 ? sql.length : commentEnd + 2;
}
return -1;
};
const findNextPlaceholder = (sql, start) => {
const sqlLength = sql.length;
for (let position = start; position < sqlLength; position++) {
const code = sql.charCodeAt(position);
if (code === charCode.questionMark)
return position;
if (code === charCode.singleQuote ||
code === charCode.backtick ||
code === charCode.dash ||
code === charCode.slash) {
const contextEnd = skipSqlContext(sql, position);
if (contextEnd !== -1)
position = contextEnd - 1;
}
}
return -1;
};
const findSetKeyword = (sql, startFrom = 0) => {
const length = sql.length;
for (let position = startFrom; position < length; position++) {
const code = sql.charCodeAt(position);
const lower = code | 32;
if (code === charCode.singleQuote ||
code === charCode.backtick ||
code === charCode.dash ||
code === charCode.slash) {
const contextEnd = skipSqlContext(sql, position);
if (contextEnd !== -1) {
position = contextEnd - 1;
continue;
}
}
if (lower === 115 && matchesWord(sql, position, 'set', length))
return position + 3;
if (lower === 107 && matchesWord(sql, position, 'key', length)) {
let cursor = position + 3;
while (cursor < length && isWhitespace(sql.charCodeAt(cursor)))
cursor++;
if (matchesWord(sql, cursor, 'update', length))
return cursor + 6;
}
}
return -1;
};
const isDate = (value) => Object.prototype.toString.call(value) === '[object Date]';
const hasSqlString = (value) => typeof value === 'object' &&
value !== null &&
'toSqlString' in value &&
typeof value.toSqlString === 'function';
const escapeString = (value) => {
regex.escapeChars.lastIndex = 0;
let chunkIndex = 0;
let escapedValue = '';
let match;
for (match = regex.escapeChars.exec(value); match !== null; match = regex.escapeChars.exec(value)) {
escapedValue += value.slice(chunkIndex, match.index);
escapedValue += CHARS_ESCAPE_MAP[match[0]];
chunkIndex = regex.escapeChars.lastIndex;
}
if (chunkIndex === 0)
return `'${value}'`;
if (chunkIndex < value.length)
return `'${escapedValue}${value.slice(chunkIndex)}'`;
return `'${escapedValue}'`;
};
const pad2 = (value) => (value < 10 ? '0' + value : '' + value);
const pad3 = (value) => value < 10 ? '00' + value : value < 100 ? '0' + value : '' + value;
const pad4 = (value) => value < 10
? '000' + value
: value < 100
? '00' + value
: value < 1000
? '0' + value
: '' + value;
const convertTimezone = (tz) => {
if (tz === 'Z')
return 0;
const timezoneMatch = tz.match(regex.timezone);
if (timezoneMatch)
return ((timezoneMatch[1] === '-' ? -1 : 1) *
(Number.parseInt(timezoneMatch[2], 10) +
(timezoneMatch[3] ? Number.parseInt(timezoneMatch[3], 10) : 0) / 60) *
60);
return false;
};
const dateToString = (date, timezone) => {
if (Number.isNaN(date.getTime()))
return 'NULL';
let year;
let month;
let day;
let hour;
let minute;
let second;
let millisecond;
if (timezone === 'local') {
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
hour = date.getHours();
minute = date.getMinutes();
second = date.getSeconds();
millisecond = date.getMilliseconds();
}
else {
const timezoneOffsetMinutes = convertTimezone(timezone);
let time = date.getTime();
if (timezoneOffsetMinutes !== false && timezoneOffsetMinutes !== 0)
time += timezoneOffsetMinutes * 60000;
const adjustedDate = new Date(time);
year = adjustedDate.getUTCFullYear();
month = adjustedDate.getUTCMonth() + 1;
day = adjustedDate.getUTCDate();
hour = adjustedDate.getUTCHours();
minute = adjustedDate.getUTCMinutes();
second = adjustedDate.getUTCSeconds();
millisecond = adjustedDate.getUTCMilliseconds();
}
// YYYY-MM-DD HH:mm:ss.mmm
return escapeString(pad4(year) +
'-' +
pad2(month) +
'-' +
pad2(day) +
' ' +
pad2(hour) +
':' +
pad2(minute) +
':' +
pad2(second) +
'.' +
pad3(millisecond));
};
exports.dateToString = dateToString;
const escapeId = (value, forbidQualified) => {
if (Array.isArray(value)) {
const length = value.length;
const parts = new Array(length);
for (let i = 0; i < length; i++)
parts[i] = (0, exports.escapeId)(value[i], forbidQualified);
return parts.join(', ');
}
const identifier = String(value);
const hasJsonOperator = identifier.indexOf('->') !== -1;
if (forbidQualified || hasJsonOperator) {
if (identifier.indexOf('`') === -1)
return `\`${identifier}\``;
return `\`${identifier.replace(regex.backtick, '``')}\``;
}
if (identifier.indexOf('`') === -1 && identifier.indexOf('.') === -1)
return `\`${identifier}\``;
return `\`${identifier
.replace(regex.backtick, '``')
.replace(regex.dot, '`.`')}\``;
};
exports.escapeId = escapeId;
const objectToValues = (object, timezone) => {
const keys = Object.keys(object);
const keysLength = keys.length;
if (keysLength === 0)
return '';
let sql = '';
for (let i = 0; i < keysLength; i++) {
const key = keys[i];
const value = object[key];
if (typeof value === 'function')
continue;
if (sql.length > 0)
sql += ', ';
sql += (0, exports.escapeId)(key);
sql += ' = ';
sql += (0, exports.escape)(value, true, timezone);
}
return sql;
};
exports.objectToValues = objectToValues;
const bufferToString = (buffer) => `X${escapeString(buffer.toString('hex'))}`;
exports.bufferToString = bufferToString;
const arrayToList = (array, timezone) => {
const length = array.length;
const parts = new Array(length);
for (let i = 0; i < length; i++) {
const value = array[i];
if (Array.isArray(value))
parts[i] = `(${(0, exports.arrayToList)(value, timezone)})`;
else
parts[i] = (0, exports.escape)(value, true, timezone);
}
return parts.join(', ');
};
exports.arrayToList = arrayToList;
const escape = (value, stringifyObjects, timezone) => {
if (value === undefined || value === null)
return 'NULL';
switch (typeof value) {
case 'boolean':
return value ? 'true' : 'false';
case 'number':
case 'bigint':
return value + '';
case 'object': {
if (isDate(value))
return (0, exports.dateToString)(value, timezone || 'local');
if (Array.isArray(value))
return (0, exports.arrayToList)(value, timezone);
if (node_buffer_1.Buffer.isBuffer(value))
return (0, exports.bufferToString)(value);
if (value instanceof Uint8Array)
return (0, exports.bufferToString)(node_buffer_1.Buffer.from(value));
if (hasSqlString(value))
return String(value.toSqlString());
if (!(stringifyObjects === undefined || stringifyObjects === null))
return escapeString(String(value));
if (isRecord(value))
return (0, exports.objectToValues)(value, timezone);
return escapeString(String(value));
}
case 'string':
return escapeString(value);
default:
return escapeString(String(value));
}
};
exports.escape = escape;
const format = (sql, values, stringifyObjects, timezone) => {
if (values === undefined || values === null)
return sql;
const valuesArray = Array.isArray(values) ? values : [values];
const length = valuesArray.length;
let setIndex = -2; // -2 = not yet computed, -1 = no SET found
let result = '';
let chunkIndex = 0;
let valuesIndex = 0;
let placeholderPosition = findNextPlaceholder(sql, 0);
while (valuesIndex < length && placeholderPosition !== -1) {
// Count consecutive question marks to detect ? vs ?? vs ???+
let placeholderEnd = placeholderPosition + 1;
let escapedValue;
while (sql.charCodeAt(placeholderEnd) === 63)
placeholderEnd++;
const placeholderLength = placeholderEnd - placeholderPosition;
const currentValue = valuesArray[valuesIndex];
if (placeholderLength > 2) {
placeholderPosition = findNextPlaceholder(sql, placeholderEnd);
continue;
}
if (placeholderLength === 2)
escapedValue = (0, exports.escapeId)(currentValue);
else if (typeof currentValue === 'number')
escapedValue = `${currentValue}`;
else if (typeof currentValue === 'object' &&
currentValue !== null &&
!stringifyObjects) {
// Lazy: compute SET position only when we first encounter an object
if (setIndex === -2)
setIndex = findSetKeyword(sql);
if (setIndex !== -1 &&
setIndex <= placeholderPosition &&
hasOnlyWhitespaceBetween(sql, setIndex, placeholderPosition) &&
!hasSqlString(currentValue) &&
!Array.isArray(currentValue) &&
!node_buffer_1.Buffer.isBuffer(currentValue) &&
!(currentValue instanceof Uint8Array) &&
!isDate(currentValue) &&
isRecord(currentValue)) {
escapedValue = (0, exports.objectToValues)(currentValue, timezone);
setIndex = findSetKeyword(sql, placeholderEnd);
}
else
escapedValue = (0, exports.escape)(currentValue, true, timezone);
}
else
escapedValue = (0, exports.escape)(currentValue, stringifyObjects, timezone);
result += sql.slice(chunkIndex, placeholderPosition);
result += escapedValue;
chunkIndex = placeholderEnd;
valuesIndex++;
placeholderPosition = findNextPlaceholder(sql, placeholderEnd);
}
if (chunkIndex === 0)
return sql;
if (chunkIndex < sql.length)
return result + sql.slice(chunkIndex);
return result;
};
exports.format = format;
const raw = (sql) => {
if (typeof sql !== 'string')
throw new TypeError('argument sql must be a string');
return {
toSqlString: () => sql,
};
};
exports.raw = raw;

View File

@@ -0,0 +1,305 @@
import { Buffer } from "node:buffer";
const regex = {
backtick: /`/g,
dot: /\./g,
timezone: /([+\-\s])(\d\d):?(\d\d)?/,
escapeChars: /[\0\b\t\n\r\x1a"'\\]/g
};
const CHARS_ESCAPE_MAP = {
"\0": "\\0",
"\b": "\\b",
" ": "\\t",
"\n": "\\n",
"\r": "\\r",
"": "\\Z",
'"': '\\"',
"'": "\\'",
"\\": "\\\\"
};
const charCode = {
singleQuote: 39,
backtick: 96,
backslash: 92,
dash: 45,
slash: 47,
asterisk: 42,
questionMark: 63,
newline: 10,
space: 32,
tab: 9,
carriageReturn: 13
};
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
const isWordChar = (code) => code >= 65 && code <= 90 || code >= 97 && code <= 122 || code >= 48 && code <= 57 || code === 95;
const isWhitespace = (code) => code === charCode.space || code === charCode.tab || code === charCode.newline || code === charCode.carriageReturn;
const hasOnlyWhitespaceBetween = (sql, start, end) => {
if (start >= end) return true;
for (let i = start; i < end; i++) {
const code = sql.charCodeAt(i);
if (code !== charCode.space && code !== charCode.tab && code !== charCode.newline && code !== charCode.carriageReturn)
return false;
}
return true;
};
const toLower = (code) => code | 32;
const matchesWord = (sql, position, word, length) => {
for (let offset = 0; offset < word.length; offset++)
if (toLower(sql.charCodeAt(position + offset)) !== word.charCodeAt(offset))
return false;
return (position === 0 || !isWordChar(sql.charCodeAt(position - 1))) && (position + word.length >= length || !isWordChar(sql.charCodeAt(position + word.length)));
};
const skipSqlContext = (sql, position) => {
const currentChar = sql.charCodeAt(position);
const nextChar = sql.charCodeAt(position + 1);
if (currentChar === charCode.singleQuote) {
for (let cursor = position + 1; cursor < sql.length; cursor++) {
if (sql.charCodeAt(cursor) === charCode.backslash) cursor++;
else if (sql.charCodeAt(cursor) === charCode.singleQuote)
return cursor + 1;
}
return sql.length;
}
if (currentChar === charCode.backtick) {
const length = sql.length;
for (let cursor = position + 1; cursor < length; cursor++) {
if (sql.charCodeAt(cursor) !== charCode.backtick) continue;
if (sql.charCodeAt(cursor + 1) === charCode.backtick) {
cursor++;
continue;
}
return cursor + 1;
}
return length;
}
if (currentChar === charCode.dash && nextChar === charCode.dash) {
const lineBreak = sql.indexOf("\n", position + 2);
return lineBreak === -1 ? sql.length : lineBreak + 1;
}
if (currentChar === charCode.slash && nextChar === charCode.asterisk) {
const commentEnd = sql.indexOf("*/", position + 2);
return commentEnd === -1 ? sql.length : commentEnd + 2;
}
return -1;
};
const findNextPlaceholder = (sql, start) => {
const sqlLength = sql.length;
for (let position = start; position < sqlLength; position++) {
const code = sql.charCodeAt(position);
if (code === charCode.questionMark) return position;
if (code === charCode.singleQuote || code === charCode.backtick || code === charCode.dash || code === charCode.slash) {
const contextEnd = skipSqlContext(sql, position);
if (contextEnd !== -1) position = contextEnd - 1;
}
}
return -1;
};
const findSetKeyword = (sql, startFrom = 0) => {
const length = sql.length;
for (let position = startFrom; position < length; position++) {
const code = sql.charCodeAt(position);
const lower = code | 32;
if (code === charCode.singleQuote || code === charCode.backtick || code === charCode.dash || code === charCode.slash) {
const contextEnd = skipSqlContext(sql, position);
if (contextEnd !== -1) {
position = contextEnd - 1;
continue;
}
}
if (lower === 115 && matchesWord(sql, position, "set", length))
return position + 3;
if (lower === 107 && matchesWord(sql, position, "key", length)) {
let cursor = position + 3;
while (cursor < length && isWhitespace(sql.charCodeAt(cursor))) cursor++;
if (matchesWord(sql, cursor, "update", length)) return cursor + 6;
}
}
return -1;
};
const isDate = (value) => Object.prototype.toString.call(value) === "[object Date]";
const hasSqlString = (value) => typeof value === "object" && value !== null && "toSqlString" in value && typeof value.toSqlString === "function";
const escapeString = (value) => {
regex.escapeChars.lastIndex = 0;
let chunkIndex = 0;
let escapedValue = "";
let match;
for (match = regex.escapeChars.exec(value); match !== null; match = regex.escapeChars.exec(value)) {
escapedValue += value.slice(chunkIndex, match.index);
escapedValue += CHARS_ESCAPE_MAP[match[0]];
chunkIndex = regex.escapeChars.lastIndex;
}
if (chunkIndex === 0) return `'${value}'`;
if (chunkIndex < value.length)
return `'${escapedValue}${value.slice(chunkIndex)}'`;
return `'${escapedValue}'`;
};
const pad2 = (value) => value < 10 ? "0" + value : "" + value;
const pad3 = (value) => value < 10 ? "00" + value : value < 100 ? "0" + value : "" + value;
const pad4 = (value) => value < 10 ? "000" + value : value < 100 ? "00" + value : value < 1e3 ? "0" + value : "" + value;
const convertTimezone = (tz) => {
if (tz === "Z") return 0;
const timezoneMatch = tz.match(regex.timezone);
if (timezoneMatch)
return (timezoneMatch[1] === "-" ? -1 : 1) * (Number.parseInt(timezoneMatch[2], 10) + (timezoneMatch[3] ? Number.parseInt(timezoneMatch[3], 10) : 0) / 60) * 60;
return false;
};
const dateToString = (date, timezone) => {
if (Number.isNaN(date.getTime())) return "NULL";
let year;
let month;
let day;
let hour;
let minute;
let second;
let millisecond;
if (timezone === "local") {
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
hour = date.getHours();
minute = date.getMinutes();
second = date.getSeconds();
millisecond = date.getMilliseconds();
} else {
const timezoneOffsetMinutes = convertTimezone(timezone);
let time = date.getTime();
if (timezoneOffsetMinutes !== false && timezoneOffsetMinutes !== 0)
time += timezoneOffsetMinutes * 6e4;
const adjustedDate = new Date(time);
year = adjustedDate.getUTCFullYear();
month = adjustedDate.getUTCMonth() + 1;
day = adjustedDate.getUTCDate();
hour = adjustedDate.getUTCHours();
minute = adjustedDate.getUTCMinutes();
second = adjustedDate.getUTCSeconds();
millisecond = adjustedDate.getUTCMilliseconds();
}
return escapeString(
pad4(year) + "-" + pad2(month) + "-" + pad2(day) + " " + pad2(hour) + ":" + pad2(minute) + ":" + pad2(second) + "." + pad3(millisecond)
);
};
const escapeId = (value, forbidQualified) => {
if (Array.isArray(value)) {
const length = value.length;
const parts = new Array(length);
for (let i = 0; i < length; i++)
parts[i] = escapeId(value[i], forbidQualified);
return parts.join(", ");
}
const identifier = String(value);
const hasJsonOperator = identifier.indexOf("->") !== -1;
if (forbidQualified || hasJsonOperator) {
if (identifier.indexOf("`") === -1) return `\`${identifier}\``;
return `\`${identifier.replace(regex.backtick, "``")}\``;
}
if (identifier.indexOf("`") === -1 && identifier.indexOf(".") === -1)
return `\`${identifier}\``;
return `\`${identifier.replace(regex.backtick, "``").replace(regex.dot, "`.`")}\``;
};
const objectToValues = (object, timezone) => {
const keys = Object.keys(object);
const keysLength = keys.length;
if (keysLength === 0) return "";
let sql = "";
for (let i = 0; i < keysLength; i++) {
const key = keys[i];
const value = object[key];
if (typeof value === "function") continue;
if (sql.length > 0) sql += ", ";
sql += escapeId(key);
sql += " = ";
sql += escape(value, true, timezone);
}
return sql;
};
const bufferToString = (buffer) => `X${escapeString(buffer.toString("hex"))}`;
const arrayToList = (array, timezone) => {
const length = array.length;
const parts = new Array(length);
for (let i = 0; i < length; i++) {
const value = array[i];
if (Array.isArray(value)) parts[i] = `(${arrayToList(value, timezone)})`;
else parts[i] = escape(value, true, timezone);
}
return parts.join(", ");
};
const escape = (value, stringifyObjects, timezone) => {
if (value === void 0 || value === null) return "NULL";
switch (typeof value) {
case "boolean":
return value ? "true" : "false";
case "number":
case "bigint":
return value + "";
case "object": {
if (isDate(value)) return dateToString(value, timezone || "local");
if (Array.isArray(value)) return arrayToList(value, timezone);
if (Buffer.isBuffer(value)) return bufferToString(value);
if (value instanceof Uint8Array)
return bufferToString(Buffer.from(value));
if (hasSqlString(value)) return String(value.toSqlString());
if (!(stringifyObjects === void 0 || stringifyObjects === null))
return escapeString(String(value));
if (isRecord(value)) return objectToValues(value, timezone);
return escapeString(String(value));
}
case "string":
return escapeString(value);
default:
return escapeString(String(value));
}
};
const format = (sql, values, stringifyObjects, timezone) => {
if (values === void 0 || values === null) return sql;
const valuesArray = Array.isArray(values) ? values : [values];
const length = valuesArray.length;
let setIndex = -2;
let result = "";
let chunkIndex = 0;
let valuesIndex = 0;
let placeholderPosition = findNextPlaceholder(sql, 0);
while (valuesIndex < length && placeholderPosition !== -1) {
let placeholderEnd = placeholderPosition + 1;
let escapedValue;
while (sql.charCodeAt(placeholderEnd) === 63) placeholderEnd++;
const placeholderLength = placeholderEnd - placeholderPosition;
const currentValue = valuesArray[valuesIndex];
if (placeholderLength > 2) {
placeholderPosition = findNextPlaceholder(sql, placeholderEnd);
continue;
}
if (placeholderLength === 2) escapedValue = escapeId(currentValue);
else if (typeof currentValue === "number") escapedValue = `${currentValue}`;
else if (typeof currentValue === "object" && currentValue !== null && !stringifyObjects) {
if (setIndex === -2) setIndex = findSetKeyword(sql);
if (setIndex !== -1 && setIndex <= placeholderPosition && hasOnlyWhitespaceBetween(sql, setIndex, placeholderPosition) && !hasSqlString(currentValue) && !Array.isArray(currentValue) && !Buffer.isBuffer(currentValue) && !(currentValue instanceof Uint8Array) && !isDate(currentValue) && isRecord(currentValue)) {
escapedValue = objectToValues(currentValue, timezone);
setIndex = findSetKeyword(sql, placeholderEnd);
} else escapedValue = escape(currentValue, true, timezone);
} else escapedValue = escape(currentValue, stringifyObjects, timezone);
result += sql.slice(chunkIndex, placeholderPosition);
result += escapedValue;
chunkIndex = placeholderEnd;
valuesIndex++;
placeholderPosition = findNextPlaceholder(sql, placeholderEnd);
}
if (chunkIndex === 0) return sql;
if (chunkIndex < sql.length) return result + sql.slice(chunkIndex);
return result;
};
const raw = (sql) => {
if (typeof sql !== "string")
throw new TypeError("argument sql must be a string");
return {
toSqlString: () => sql
};
};
export {
arrayToList,
bufferToString,
dateToString,
escape,
escapeId,
format,
objectToValues,
raw
};

View File

@@ -0,0 +1,5 @@
export type Raw = {
toSqlString(): string;
};
export type SqlValue = string | number | bigint | boolean | Date | Buffer | Uint8Array | Raw | Record<string, unknown> | SqlValue[] | null | undefined;
export type Timezone = 'local' | 'Z' | (string & NonNullable<unknown>);

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });