prompts.chat 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +2 -0
- package/dist/builder/{index.mjs → index.cjs} +42 -3
- package/dist/builder/index.cjs.map +1 -0
- package/dist/builder/index.js +2 -41
- package/dist/builder/index.js.map +1 -1
- package/dist/cli/index.js +1132 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/{index.mjs → index.cjs} +72 -13
- package/dist/index.cjs.map +1 -0
- package/dist/{index.d.mts → index.d.cts} +5 -5
- package/dist/index.js +12 -71
- package/dist/index.js.map +1 -1
- package/dist/parser/{index.mjs → index.cjs} +32 -3
- package/dist/parser/{index.mjs.map → index.cjs.map} +1 -1
- package/dist/parser/{index.d.mts → index.d.cts} +1 -1
- package/dist/parser/index.js +2 -31
- package/dist/parser/index.js.map +1 -1
- package/dist/quality/{index.mjs → index.cjs} +31 -3
- package/dist/quality/{index.mjs.map → index.cjs.map} +1 -1
- package/dist/quality/{index.d.mts → index.d.cts} +1 -1
- package/dist/quality/index.js +2 -30
- package/dist/quality/index.js.map +1 -1
- package/dist/similarity/{index.mjs → index.cjs} +35 -3
- package/dist/similarity/{index.mjs.map → index.cjs.map} +1 -1
- package/dist/similarity/{index.d.mts → index.d.cts} +1 -1
- package/dist/similarity/index.js +2 -34
- package/dist/similarity/index.js.map +1 -1
- package/dist/variables/{index.mjs → index.cjs} +35 -3
- package/dist/variables/{index.mjs.map → index.cjs.map} +1 -1
- package/dist/variables/{index.d.mts → index.d.cts} +1 -1
- package/dist/variables/index.js +2 -34
- package/dist/variables/index.js.map +1 -1
- package/package.json +18 -1
- package/dist/builder/index.mjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- /package/dist/builder/{index.d.mts → index.d.cts} +0 -0
- /package/dist/{index-BEIO8LCd.d.mts → index-BEIO8LCd.d.cts} +0 -0
- /package/dist/{index-CSHEKYfQ.d.mts → index-CSHEKYfQ.d.cts} +0 -0
- /package/dist/{index-D41E6D9X.d.mts → index-D41E6D9X.d.cts} +0 -0
- /package/dist/{index-DOz8zcA0.d.mts → index-DOz8zcA0.d.cts} +0 -0
package/dist/similarity/index.js
CHANGED
|
@@ -1,35 +1,4 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
1
|
// src/similarity/index.ts
|
|
21
|
-
var similarity_exports = {};
|
|
22
|
-
__export(similarity_exports, {
|
|
23
|
-
calculate: () => calculate,
|
|
24
|
-
calculateSimilarity: () => calculateSimilarity,
|
|
25
|
-
deduplicate: () => deduplicate,
|
|
26
|
-
findDuplicates: () => findDuplicates,
|
|
27
|
-
getContentFingerprint: () => getContentFingerprint,
|
|
28
|
-
isDuplicate: () => isDuplicate,
|
|
29
|
-
isSimilarContent: () => isSimilarContent,
|
|
30
|
-
normalizeContent: () => normalizeContent
|
|
31
|
-
});
|
|
32
|
-
module.exports = __toCommonJS(similarity_exports);
|
|
33
2
|
function normalizeContent(content) {
|
|
34
3
|
return content.replace(/\$\{[^}]+\}/g, "").replace(/\[[^\]]+\]/g, "").replace(/<[^>]+>/g, "").toLowerCase().replace(/[^\w\s]/g, "").replace(/\s+/g, " ").trim();
|
|
35
4
|
}
|
|
@@ -109,8 +78,7 @@ function deduplicate(prompts, threshold = 0.85) {
|
|
|
109
78
|
}
|
|
110
79
|
return result;
|
|
111
80
|
}
|
|
112
|
-
|
|
113
|
-
0 && (module.exports = {
|
|
81
|
+
export {
|
|
114
82
|
calculate,
|
|
115
83
|
calculateSimilarity,
|
|
116
84
|
deduplicate,
|
|
@@ -119,5 +87,5 @@ function deduplicate(prompts, threshold = 0.85) {
|
|
|
119
87
|
isDuplicate,
|
|
120
88
|
isSimilarContent,
|
|
121
89
|
normalizeContent
|
|
122
|
-
}
|
|
90
|
+
};
|
|
123
91
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/similarity/index.ts"],"sourcesContent":["/**\n * Content similarity utilities for duplicate detection\n */\n\n/**\n * Normalize content for comparison by:\n * - Removing variables (${...} patterns)\n * - Converting to lowercase\n * - Removing extra whitespace\n * - Removing punctuation\n */\nexport function normalizeContent(content: string): string {\n return content\n // Remove variables like ${variable} or ${variable:default}\n .replace(/\\$\\{[^}]+\\}/g, \"\")\n // Remove common placeholder patterns like [placeholder] or <placeholder>\n .replace(/\\[[^\\]]+\\]/g, \"\")\n .replace(/<[^>]+>/g, \"\")\n // Convert to lowercase\n .toLowerCase()\n // Remove punctuation\n .replace(/[^\\w\\s]/g, \"\")\n // Normalize whitespace\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * Calculate Jaccard similarity between two strings\n * Returns a value between 0 (completely different) and 1 (identical)\n */\nfunction jaccardSimilarity(str1: string, str2: string): number {\n const set1 = new Set(str1.split(\" \").filter(Boolean));\n const set2 = new Set(str2.split(\" \").filter(Boolean));\n \n if (set1.size === 0 && set2.size === 0) return 1;\n if (set1.size === 0 || set2.size === 0) return 0;\n \n const intersection = new Set([...set1].filter(x => set2.has(x)));\n const union = new Set([...set1, ...set2]);\n \n return intersection.size / union.size;\n}\n\n/**\n * Calculate n-gram similarity for better sequence matching\n * Uses trigrams (3-character sequences) by default\n */\nfunction ngramSimilarity(str1: string, str2: string, n: number = 3): number {\n const getNgrams = (str: string): Set<string> => {\n const ngrams = new Set<string>();\n const padded = \" \".repeat(n - 1) + str + \" \".repeat(n - 1);\n for (let i = 0; i <= padded.length - n; i++) {\n ngrams.add(padded.slice(i, i + n));\n }\n return ngrams;\n };\n \n const ngrams1 = getNgrams(str1);\n const ngrams2 = getNgrams(str2);\n \n if (ngrams1.size === 0 && ngrams2.size === 0) return 1;\n if (ngrams1.size === 0 || ngrams2.size === 0) return 0;\n \n const intersection = new Set([...ngrams1].filter(x => ngrams2.has(x)));\n const union = new Set([...ngrams1, ...ngrams2]);\n \n return intersection.size / union.size;\n}\n\n/**\n * Combined similarity score using multiple algorithms\n * Returns a value between 0 (completely different) and 1 (identical)\n */\nexport function calculateSimilarity(content1: string, content2: string): number {\n const normalized1 = normalizeContent(content1);\n const normalized2 = normalizeContent(content2);\n \n // Exact match after normalization\n if (normalized1 === normalized2) return 1;\n \n // Empty content edge case\n if (!normalized1 || !normalized2) return 0;\n \n // Combine Jaccard (word-level) and n-gram (character-level) similarities\n const jaccard = jaccardSimilarity(normalized1, normalized2);\n const ngram = ngramSimilarity(normalized1, normalized2);\n \n // Weighted average: 60% Jaccard (word overlap), 40% n-gram (sequence similarity)\n return jaccard * 0.6 + ngram * 0.4;\n}\n\n/**\n * Alias for calculateSimilarity\n */\nexport const calculate = calculateSimilarity;\n\n/**\n * Check if two contents are similar enough to be considered duplicates\n * Default threshold is 0.85 (85% similar)\n */\nexport function isSimilarContent(\n content1: string, \n content2: string, \n threshold: number = 0.85\n): boolean {\n return calculateSimilarity(content1, content2) >= threshold;\n}\n\n/**\n * Alias for isSimilarContent\n */\nexport const isDuplicate = isSimilarContent;\n\n/**\n * Get normalized content hash for database indexing/comparison\n * This is a simple hash for quick lookups before full similarity check\n */\nexport function getContentFingerprint(content: string): string {\n const normalized = normalizeContent(content);\n // Take first 500 chars of normalized content as fingerprint\n return normalized.slice(0, 500);\n}\n\n/**\n * Find duplicates in an array of prompts\n * Returns groups of similar prompts\n */\nexport function findDuplicates<T extends { content: string }>(\n prompts: T[],\n threshold: number = 0.85\n): T[][] {\n const groups: T[][] = [];\n const used = new Set<number>();\n\n for (let i = 0; i < prompts.length; i++) {\n if (used.has(i)) continue;\n\n const group: T[] = [prompts[i]];\n used.add(i);\n\n for (let j = i + 1; j < prompts.length; j++) {\n if (used.has(j)) continue;\n\n if (isSimilarContent(prompts[i].content, prompts[j].content, threshold)) {\n group.push(prompts[j]);\n used.add(j);\n }\n }\n\n if (group.length > 1) {\n groups.push(group);\n }\n }\n\n return groups;\n}\n\n/**\n * Deduplicate an array of prompts, keeping the first occurrence\n */\nexport function deduplicate<T extends { content: string }>(\n prompts: T[],\n threshold: number = 0.85\n): T[] {\n const result: T[] = [];\n\n for (const prompt of prompts) {\n const isDupe = result.some(existing => \n isSimilarContent(existing.content, prompt.content, threshold)\n );\n\n if (!isDupe) {\n result.push(prompt);\n }\n }\n\n return result;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/similarity/index.ts"],"sourcesContent":["/**\n * Content similarity utilities for duplicate detection\n */\n\n/**\n * Normalize content for comparison by:\n * - Removing variables (${...} patterns)\n * - Converting to lowercase\n * - Removing extra whitespace\n * - Removing punctuation\n */\nexport function normalizeContent(content: string): string {\n return content\n // Remove variables like ${variable} or ${variable:default}\n .replace(/\\$\\{[^}]+\\}/g, \"\")\n // Remove common placeholder patterns like [placeholder] or <placeholder>\n .replace(/\\[[^\\]]+\\]/g, \"\")\n .replace(/<[^>]+>/g, \"\")\n // Convert to lowercase\n .toLowerCase()\n // Remove punctuation\n .replace(/[^\\w\\s]/g, \"\")\n // Normalize whitespace\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * Calculate Jaccard similarity between two strings\n * Returns a value between 0 (completely different) and 1 (identical)\n */\nfunction jaccardSimilarity(str1: string, str2: string): number {\n const set1 = new Set(str1.split(\" \").filter(Boolean));\n const set2 = new Set(str2.split(\" \").filter(Boolean));\n \n if (set1.size === 0 && set2.size === 0) return 1;\n if (set1.size === 0 || set2.size === 0) return 0;\n \n const intersection = new Set([...set1].filter(x => set2.has(x)));\n const union = new Set([...set1, ...set2]);\n \n return intersection.size / union.size;\n}\n\n/**\n * Calculate n-gram similarity for better sequence matching\n * Uses trigrams (3-character sequences) by default\n */\nfunction ngramSimilarity(str1: string, str2: string, n: number = 3): number {\n const getNgrams = (str: string): Set<string> => {\n const ngrams = new Set<string>();\n const padded = \" \".repeat(n - 1) + str + \" \".repeat(n - 1);\n for (let i = 0; i <= padded.length - n; i++) {\n ngrams.add(padded.slice(i, i + n));\n }\n return ngrams;\n };\n \n const ngrams1 = getNgrams(str1);\n const ngrams2 = getNgrams(str2);\n \n if (ngrams1.size === 0 && ngrams2.size === 0) return 1;\n if (ngrams1.size === 0 || ngrams2.size === 0) return 0;\n \n const intersection = new Set([...ngrams1].filter(x => ngrams2.has(x)));\n const union = new Set([...ngrams1, ...ngrams2]);\n \n return intersection.size / union.size;\n}\n\n/**\n * Combined similarity score using multiple algorithms\n * Returns a value between 0 (completely different) and 1 (identical)\n */\nexport function calculateSimilarity(content1: string, content2: string): number {\n const normalized1 = normalizeContent(content1);\n const normalized2 = normalizeContent(content2);\n \n // Exact match after normalization\n if (normalized1 === normalized2) return 1;\n \n // Empty content edge case\n if (!normalized1 || !normalized2) return 0;\n \n // Combine Jaccard (word-level) and n-gram (character-level) similarities\n const jaccard = jaccardSimilarity(normalized1, normalized2);\n const ngram = ngramSimilarity(normalized1, normalized2);\n \n // Weighted average: 60% Jaccard (word overlap), 40% n-gram (sequence similarity)\n return jaccard * 0.6 + ngram * 0.4;\n}\n\n/**\n * Alias for calculateSimilarity\n */\nexport const calculate = calculateSimilarity;\n\n/**\n * Check if two contents are similar enough to be considered duplicates\n * Default threshold is 0.85 (85% similar)\n */\nexport function isSimilarContent(\n content1: string, \n content2: string, \n threshold: number = 0.85\n): boolean {\n return calculateSimilarity(content1, content2) >= threshold;\n}\n\n/**\n * Alias for isSimilarContent\n */\nexport const isDuplicate = isSimilarContent;\n\n/**\n * Get normalized content hash for database indexing/comparison\n * This is a simple hash for quick lookups before full similarity check\n */\nexport function getContentFingerprint(content: string): string {\n const normalized = normalizeContent(content);\n // Take first 500 chars of normalized content as fingerprint\n return normalized.slice(0, 500);\n}\n\n/**\n * Find duplicates in an array of prompts\n * Returns groups of similar prompts\n */\nexport function findDuplicates<T extends { content: string }>(\n prompts: T[],\n threshold: number = 0.85\n): T[][] {\n const groups: T[][] = [];\n const used = new Set<number>();\n\n for (let i = 0; i < prompts.length; i++) {\n if (used.has(i)) continue;\n\n const group: T[] = [prompts[i]];\n used.add(i);\n\n for (let j = i + 1; j < prompts.length; j++) {\n if (used.has(j)) continue;\n\n if (isSimilarContent(prompts[i].content, prompts[j].content, threshold)) {\n group.push(prompts[j]);\n used.add(j);\n }\n }\n\n if (group.length > 1) {\n groups.push(group);\n }\n }\n\n return groups;\n}\n\n/**\n * Deduplicate an array of prompts, keeping the first occurrence\n */\nexport function deduplicate<T extends { content: string }>(\n prompts: T[],\n threshold: number = 0.85\n): T[] {\n const result: T[] = [];\n\n for (const prompt of prompts) {\n const isDupe = result.some(existing => \n isSimilarContent(existing.content, prompt.content, threshold)\n );\n\n if (!isDupe) {\n result.push(prompt);\n }\n }\n\n return result;\n}\n"],"mappings":";AAWO,SAAS,iBAAiB,SAAyB;AACxD,SAAO,QAEJ,QAAQ,gBAAgB,EAAE,EAE1B,QAAQ,eAAe,EAAE,EACzB,QAAQ,YAAY,EAAE,EAEtB,YAAY,EAEZ,QAAQ,YAAY,EAAE,EAEtB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAMA,SAAS,kBAAkB,MAAc,MAAsB;AAC7D,QAAM,OAAO,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC;AACpD,QAAM,OAAO,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC;AAEpD,MAAI,KAAK,SAAS,KAAK,KAAK,SAAS,EAAG,QAAO;AAC/C,MAAI,KAAK,SAAS,KAAK,KAAK,SAAS,EAAG,QAAO;AAE/C,QAAM,eAAe,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,OAAK,KAAK,IAAI,CAAC,CAAC,CAAC;AAC/D,QAAM,QAAQ,oBAAI,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;AAExC,SAAO,aAAa,OAAO,MAAM;AACnC;AAMA,SAAS,gBAAgB,MAAc,MAAc,IAAY,GAAW;AAC1E,QAAM,YAAY,CAAC,QAA6B;AAC9C,UAAM,SAAS,oBAAI,IAAY;AAC/B,UAAM,SAAS,IAAI,OAAO,IAAI,CAAC,IAAI,MAAM,IAAI,OAAO,IAAI,CAAC;AACzD,aAAS,IAAI,GAAG,KAAK,OAAO,SAAS,GAAG,KAAK;AAC3C,aAAO,IAAI,OAAO,MAAM,GAAG,IAAI,CAAC,CAAC;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,UAAU,IAAI;AAC9B,QAAM,UAAU,UAAU,IAAI;AAE9B,MAAI,QAAQ,SAAS,KAAK,QAAQ,SAAS,EAAG,QAAO;AACrD,MAAI,QAAQ,SAAS,KAAK,QAAQ,SAAS,EAAG,QAAO;AAErD,QAAM,eAAe,IAAI,IAAI,CAAC,GAAG,OAAO,EAAE,OAAO,OAAK,QAAQ,IAAI,CAAC,CAAC,CAAC;AACrE,QAAM,QAAQ,oBAAI,IAAI,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC;AAE9C,SAAO,aAAa,OAAO,MAAM;AACnC;AAMO,SAAS,oBAAoB,UAAkB,UAA0B;AAC9E,QAAM,cAAc,iBAAiB,QAAQ;AAC7C,QAAM,cAAc,iBAAiB,QAAQ;AAG7C,MAAI,gBAAgB,YAAa,QAAO;AAGxC,MAAI,CAAC,eAAe,CAAC,YAAa,QAAO;AAGzC,QAAM,UAAU,kBAAkB,aAAa,WAAW;AAC1D,QAAM,QAAQ,gBAAgB,aAAa,WAAW;AAGtD,SAAO,UAAU,MAAM,QAAQ;AACjC;AAKO,IAAM,YAAY;AAMlB,SAAS,iBACd,UACA,UACA,YAAoB,MACX;AACT,SAAO,oBAAoB,UAAU,QAAQ,KAAK;AACpD;AAKO,IAAM,cAAc;AAMpB,SAAS,sBAAsB,SAAyB;AAC7D,QAAM,aAAa,iBAAiB,OAAO;AAE3C,SAAO,WAAW,MAAM,GAAG,GAAG;AAChC;AAMO,SAAS,eACd,SACA,YAAoB,MACb;AACP,QAAM,SAAgB,CAAC;AACvB,QAAM,OAAO,oBAAI,IAAY;AAE7B,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,QAAI,KAAK,IAAI,CAAC,EAAG;AAEjB,UAAM,QAAa,CAAC,QAAQ,CAAC,CAAC;AAC9B,SAAK,IAAI,CAAC;AAEV,aAAS,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AAC3C,UAAI,KAAK,IAAI,CAAC,EAAG;AAEjB,UAAI,iBAAiB,QAAQ,CAAC,EAAE,SAAS,QAAQ,CAAC,EAAE,SAAS,SAAS,GAAG;AACvE,cAAM,KAAK,QAAQ,CAAC,CAAC;AACrB,aAAK,IAAI,CAAC;AAAA,MACZ;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,YACd,SACA,YAAoB,MACf;AACL,QAAM,SAAc,CAAC;AAErB,aAAW,UAAU,SAAS;AAC5B,UAAM,SAAS,OAAO;AAAA,MAAK,cACzB,iBAAiB,SAAS,SAAS,OAAO,SAAS,SAAS;AAAA,IAC9D;AAEA,QAAI,CAAC,QAAQ;AACX,aAAO,KAAK,MAAM;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -1,4 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
1
20
|
// src/variables/index.ts
|
|
21
|
+
var variables_exports = {};
|
|
22
|
+
__export(variables_exports, {
|
|
23
|
+
compile: () => compile,
|
|
24
|
+
convertAllVariables: () => convertAllVariables,
|
|
25
|
+
convertToSupportedFormat: () => convertToSupportedFormat,
|
|
26
|
+
detect: () => detect,
|
|
27
|
+
detectVariables: () => detectVariables,
|
|
28
|
+
extractVariables: () => extractVariables,
|
|
29
|
+
getPatternDescription: () => getPatternDescription,
|
|
30
|
+
normalize: () => normalize
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(variables_exports);
|
|
2
33
|
var PATTERNS = [
|
|
3
34
|
// Double bracket: [[name]] or [[ name ]] or [[name: default]]
|
|
4
35
|
{
|
|
@@ -261,7 +292,8 @@ function compile(template, values, options = {}) {
|
|
|
261
292
|
}
|
|
262
293
|
);
|
|
263
294
|
}
|
|
264
|
-
export
|
|
295
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
296
|
+
0 && (module.exports = {
|
|
265
297
|
compile,
|
|
266
298
|
convertAllVariables,
|
|
267
299
|
convertToSupportedFormat,
|
|
@@ -270,5 +302,5 @@ export {
|
|
|
270
302
|
extractVariables,
|
|
271
303
|
getPatternDescription,
|
|
272
304
|
normalize
|
|
273
|
-
};
|
|
274
|
-
//# sourceMappingURL=index.
|
|
305
|
+
});
|
|
306
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/variables/index.ts"],"sourcesContent":["/**\n * Variable Detection Utility\n * Detects common variable-like patterns in text that could be converted\n * to our supported format: ${variableName} or ${variableName:default}\n */\n\nexport interface DetectedVariable {\n original: string;\n name: string;\n defaultValue?: string;\n pattern: VariablePattern;\n startIndex: number;\n endIndex: number;\n}\n\nexport type VariablePattern = \n | \"double_bracket\" // [[name]] or [[ name ]]\n | \"double_curly\" // {{name}} or {{ name }}\n | \"single_bracket\" // [NAME] or [name]\n | \"single_curly\" // {NAME} or {name}\n | \"angle_bracket\" // <NAME> or <name>\n | \"percent\" // %NAME% or %name%\n | \"dollar_curly\"; // ${name} (already our format)\n\ninterface PatternConfig {\n pattern: VariablePattern;\n regex: RegExp;\n extractName: (match: RegExpExecArray) => string;\n extractDefault?: (match: RegExpExecArray) => string | undefined;\n}\n\n// Patterns to detect, ordered by specificity (more specific first)\nconst PATTERNS: PatternConfig[] = [\n // Double bracket: [[name]] or [[ name ]] or [[name: default]]\n {\n pattern: \"double_bracket\",\n regex: /\\[\\[\\s*([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?:\\s*:\\s*([^\\]]*?))?\\s*\\]\\]/g,\n extractName: (m) => m[1].trim(),\n extractDefault: (m) => m[2]?.trim(),\n },\n // Double curly: {{name}} or {{ name }} or {{name: default}}\n {\n pattern: \"double_curly\",\n regex: /\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?:\\s*:\\s*([^}]*?))?\\s*\\}\\}/g,\n extractName: (m) => m[1].trim(),\n extractDefault: (m) => m[2]?.trim(),\n },\n // Our supported format (to exclude from warnings)\n {\n pattern: \"dollar_curly\",\n regex: /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g,\n extractName: (m) => m[1].trim(),\n },\n // Single bracket with uppercase or placeholder-like: [NAME] or [Your Name]\n {\n pattern: \"single_bracket\",\n regex: /\\[([A-Z][A-Z0-9_\\s]*|[A-Za-z][a-zA-Z0-9_]*(?:\\s+[A-Za-z][a-zA-Z0-9_]*)*)\\]/g,\n extractName: (m) => m[1].trim(),\n },\n // Single curly with uppercase: {NAME} or {Your Name}\n {\n pattern: \"single_curly\",\n regex: /\\{([A-Z][A-Z0-9_\\s]*|[A-Za-z][a-zA-Z0-9_]*(?:\\s+[A-Za-z][a-zA-Z0-9_]*)*)\\}/g,\n extractName: (m) => m[1].trim(),\n },\n // Angle brackets: <NAME> or <name>\n {\n pattern: \"angle_bracket\",\n regex: /<([A-Z][A-Z0-9_\\s]*|[a-zA-Z_][a-zA-Z0-9_\\s]*)>/g,\n extractName: (m) => m[1].trim(),\n },\n // Percent signs: %NAME% or %name%\n {\n pattern: \"percent\",\n regex: /%([a-zA-Z_][a-zA-Z0-9_]*)%/g,\n extractName: (m) => m[1].trim(),\n },\n];\n\n// Common false positives to ignore\nconst FALSE_POSITIVES = new Set([\n // HTML/XML common tags\n \"div\", \"span\", \"p\", \"a\", \"br\", \"hr\", \"img\", \"input\", \"button\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"ul\", \"ol\", \"li\", \"table\",\n \"tr\", \"td\", \"th\", \"thead\", \"tbody\", \"form\", \"label\", \"select\",\n \"option\", \"textarea\", \"script\", \"style\", \"link\", \"meta\", \"head\",\n \"body\", \"html\", \"section\", \"article\", \"nav\", \"header\", \"footer\",\n \"main\", \"aside\", \"figure\", \"figcaption\", \"strong\", \"em\", \"code\",\n \"pre\", \"blockquote\", \"cite\", \"abbr\", \"address\", \"b\", \"i\", \"u\",\n // Common programming constructs\n \"if\", \"else\", \"for\", \"while\", \"switch\", \"case\", \"break\", \"return\",\n \"function\", \"class\", \"const\", \"let\", \"var\", \"import\", \"export\",\n \"default\", \"try\", \"catch\", \"finally\", \"throw\", \"new\", \"this\",\n \"null\", \"undefined\", \"true\", \"false\", \"typeof\", \"instanceof\",\n // JSON structure keywords (when in context)\n \"type\", \"id\", \"key\", \"value\", \"data\", \"items\", \"properties\",\n]);\n\n/**\n * Check if we're inside a JSON string context\n */\nfunction isInsideJsonString(text: string, index: number): boolean {\n let inString = false;\n for (let i = 0; i < index; i++) {\n if (text[i] === '\"' && (i === 0 || text[i - 1] !== '\\\\')) {\n inString = !inString;\n }\n }\n return inString;\n}\n\n/**\n * Detect variable-like patterns in text\n * Returns detected variables that are NOT in our supported format\n */\nexport function detectVariables(text: string): DetectedVariable[] {\n const detected: DetectedVariable[] = [];\n const seenRanges: Array<[number, number]> = [];\n \n // Track our supported format positions to exclude them\n const supportedVars = new Set<string>();\n const dollarCurlyPattern = /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g;\n let match: RegExpExecArray | null;\n \n while ((match = dollarCurlyPattern.exec(text)) !== null) {\n seenRanges.push([match.index, match.index + match[0].length]);\n supportedVars.add(match[0]);\n }\n \n // Check each pattern\n for (const config of PATTERNS) {\n // Skip our supported format pattern for detection\n if (config.pattern === \"dollar_curly\") continue;\n \n const regex = new RegExp(config.regex.source, config.regex.flags);\n \n while ((match = regex.exec(text)) !== null) {\n const startIndex = match.index;\n const endIndex = startIndex + match[0].length;\n \n // Check if this range overlaps with any already detected range\n const overlaps = seenRanges.some(\n ([start, end]) => \n (startIndex >= start && startIndex < end) ||\n (endIndex > start && endIndex <= end)\n );\n \n if (overlaps) continue;\n \n const name = config.extractName(match);\n \n // Skip false positives\n if (FALSE_POSITIVES.has(name.toLowerCase())) continue;\n \n // Skip very short names (likely not variables)\n if (name.length < 2) continue;\n \n // For angle brackets, be more strict\n if (config.pattern === \"angle_bracket\") {\n if (!/^[A-Z]/.test(name) && !name.includes(\" \")) continue;\n }\n \n // For single curly/bracket in JSON context, be more careful\n if (\n (config.pattern === \"single_curly\" || config.pattern === \"single_bracket\") &&\n isInsideJsonString(text, startIndex)\n ) {\n if (!/^[A-Z]/.test(name) && !name.includes(\" \")) continue;\n }\n \n const defaultValue = config.extractDefault?.(match);\n \n detected.push({\n original: match[0],\n name,\n defaultValue,\n pattern: config.pattern,\n startIndex,\n endIndex,\n });\n \n seenRanges.push([startIndex, endIndex]);\n }\n }\n \n // Sort by position and remove duplicates\n return detected\n .sort((a, b) => a.startIndex - b.startIndex)\n .filter((v, i, arr) => \n i === 0 || v.original !== arr[i - 1].original || v.startIndex !== arr[i - 1].startIndex\n );\n}\n\n/**\n * Convert a detected variable to our supported format\n */\nexport function convertToSupportedFormat(variable: DetectedVariable): string {\n // Normalize name: lowercase, replace spaces with underscores\n const normalizedName = variable.name\n .toLowerCase()\n .replace(/\\s+/g, \"_\")\n .replace(/[^a-z0-9_]/g, \"\");\n \n if (variable.defaultValue) {\n return `\\${${normalizedName}:${variable.defaultValue}}`;\n }\n \n return `\\${${normalizedName}}`;\n}\n\n/**\n * Convert all detected variables in text to our supported format\n */\nexport function convertAllVariables(text: string): string {\n const detected = detectVariables(text);\n \n if (detected.length === 0) return text;\n \n // Sort by position descending to replace from end to start\n const sorted = [...detected].sort((a, b) => b.startIndex - a.startIndex);\n \n let result = text;\n for (const variable of sorted) {\n const converted = convertToSupportedFormat(variable);\n result = result.slice(0, variable.startIndex) + converted + result.slice(variable.endIndex);\n }\n \n return result;\n}\n\n/**\n * Alias for convertAllVariables - normalizes all variable formats to ${var}\n */\nexport const normalize = convertAllVariables;\n\n/**\n * Alias for detectVariables\n */\nexport const detect = detectVariables;\n\n/**\n * Get a human-readable pattern description\n */\nexport function getPatternDescription(pattern: VariablePattern): string {\n switch (pattern) {\n case \"double_bracket\": return \"[[...]]\";\n case \"double_curly\": return \"{{...}}\";\n case \"single_bracket\": return \"[...]\";\n case \"single_curly\": return \"{...}\";\n case \"angle_bracket\": return \"<...>\";\n case \"percent\": return \"%...%\";\n case \"dollar_curly\": return \"${...}\";\n }\n}\n\n/**\n * Extract variables from our supported ${var} or ${var:default} format\n */\nexport function extractVariables(text: string): Array<{ name: string; defaultValue?: string }> {\n const regex = /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g;\n const variables: Array<{ name: string; defaultValue?: string }> = [];\n let match: RegExpExecArray | null;\n \n while ((match = regex.exec(text)) !== null) {\n variables.push({\n name: match[1].trim(),\n defaultValue: match[2]?.trim(),\n });\n }\n \n return variables;\n}\n\n/**\n * Compile a prompt template with variable values\n */\nexport function compile(\n template: string, \n values: Record<string, string>,\n options: { useDefaults?: boolean } = {}\n): string {\n const { useDefaults = true } = options;\n \n return template.replace(\n /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g,\n (match, name, defaultValue) => {\n const trimmedName = name.trim();\n if (trimmedName in values) {\n return values[trimmedName];\n }\n if (useDefaults && defaultValue !== undefined) {\n return defaultValue.trim();\n }\n return match; // Keep original if no value and no default\n }\n );\n}\n"],"mappings":";AAgCA,IAAM,WAA4B;AAAA;AAAA,EAEhC;AAAA,IACE,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK;AAAA,IAC9B,gBAAgB,CAAC,MAAM,EAAE,CAAC,GAAG,KAAK;AAAA,EACpC;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK;AAAA,IAC9B,gBAAgB,CAAC,MAAM,EAAE,CAAC,GAAG,KAAK;AAAA,EACpC;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK;AAAA,EAChC;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK;AAAA,EAChC;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK;AAAA,EAChC;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK;AAAA,EAChC;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK;AAAA,EAChC;AACF;AAGA,IAAM,kBAAkB,oBAAI,IAAI;AAAA;AAAA,EAE9B;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAK;AAAA,EAAK;AAAA,EAAM;AAAA,EAAM;AAAA,EAAO;AAAA,EAAS;AAAA,EACrD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACtD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAS;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AAAA,EACrD;AAAA,EAAU;AAAA,EAAY;AAAA,EAAU;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACzD;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAW;AAAA,EAAO;AAAA,EAAU;AAAA,EACvD;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAU;AAAA,EAAc;AAAA,EAAU;AAAA,EAAM;AAAA,EACzD;AAAA,EAAO;AAAA,EAAc;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAK;AAAA,EAAK;AAAA;AAAA,EAE1D;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAS;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAS;AAAA,EACzD;AAAA,EAAY;AAAA,EAAS;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EACtD;AAAA,EAAW;AAAA,EAAO;AAAA,EAAS;AAAA,EAAW;AAAA,EAAS;AAAA,EAAO;AAAA,EACtD;AAAA,EAAQ;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAU;AAAA;AAAA,EAEhD;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAO;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAS;AACjD,CAAC;AAKD,SAAS,mBAAmB,MAAc,OAAwB;AAChE,MAAI,WAAW;AACf,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,QAAI,KAAK,CAAC,MAAM,QAAQ,MAAM,KAAK,KAAK,IAAI,CAAC,MAAM,OAAO;AACxD,iBAAW,CAAC;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,gBAAgB,MAAkC;AAChE,QAAM,WAA+B,CAAC;AACtC,QAAM,aAAsC,CAAC;AAG7C,QAAM,gBAAgB,oBAAI,IAAY;AACtC,QAAM,qBAAqB;AAC3B,MAAI;AAEJ,UAAQ,QAAQ,mBAAmB,KAAK,IAAI,OAAO,MAAM;AACvD,eAAW,KAAK,CAAC,MAAM,OAAO,MAAM,QAAQ,MAAM,CAAC,EAAE,MAAM,CAAC;AAC5D,kBAAc,IAAI,MAAM,CAAC,CAAC;AAAA,EAC5B;AAGA,aAAW,UAAU,UAAU;AAE7B,QAAI,OAAO,YAAY,eAAgB;AAEvC,UAAM,QAAQ,IAAI,OAAO,OAAO,MAAM,QAAQ,OAAO,MAAM,KAAK;AAEhE,YAAQ,QAAQ,MAAM,KAAK,IAAI,OAAO,MAAM;AAC1C,YAAM,aAAa,MAAM;AACzB,YAAM,WAAW,aAAa,MAAM,CAAC,EAAE;AAGvC,YAAM,WAAW,WAAW;AAAA,QAC1B,CAAC,CAAC,OAAO,GAAG,MACT,cAAc,SAAS,aAAa,OACpC,WAAW,SAAS,YAAY;AAAA,MACrC;AAEA,UAAI,SAAU;AAEd,YAAM,OAAO,OAAO,YAAY,KAAK;AAGrC,UAAI,gBAAgB,IAAI,KAAK,YAAY,CAAC,EAAG;AAG7C,UAAI,KAAK,SAAS,EAAG;AAGrB,UAAI,OAAO,YAAY,iBAAiB;AACtC,YAAI,CAAC,SAAS,KAAK,IAAI,KAAK,CAAC,KAAK,SAAS,GAAG,EAAG;AAAA,MACnD;AAGA,WACG,OAAO,YAAY,kBAAkB,OAAO,YAAY,qBACzD,mBAAmB,MAAM,UAAU,GACnC;AACA,YAAI,CAAC,SAAS,KAAK,IAAI,KAAK,CAAC,KAAK,SAAS,GAAG,EAAG;AAAA,MACnD;AAEA,YAAM,eAAe,OAAO,iBAAiB,KAAK;AAElD,eAAS,KAAK;AAAA,QACZ,UAAU,MAAM,CAAC;AAAA,QACjB;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,QAChB;AAAA,QACA;AAAA,MACF,CAAC;AAED,iBAAW,KAAK,CAAC,YAAY,QAAQ,CAAC;AAAA,IACxC;AAAA,EACF;AAGA,SAAO,SACJ,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU,EAC1C;AAAA,IAAO,CAAC,GAAG,GAAG,QACb,MAAM,KAAK,EAAE,aAAa,IAAI,IAAI,CAAC,EAAE,YAAY,EAAE,eAAe,IAAI,IAAI,CAAC,EAAE;AAAA,EAC/E;AACJ;AAKO,SAAS,yBAAyB,UAAoC;AAE3E,QAAM,iBAAiB,SAAS,KAC7B,YAAY,EACZ,QAAQ,QAAQ,GAAG,EACnB,QAAQ,eAAe,EAAE;AAE5B,MAAI,SAAS,cAAc;AACzB,WAAO,MAAM,cAAc,IAAI,SAAS,YAAY;AAAA,EACtD;AAEA,SAAO,MAAM,cAAc;AAC7B;AAKO,SAAS,oBAAoB,MAAsB;AACxD,QAAM,WAAW,gBAAgB,IAAI;AAErC,MAAI,SAAS,WAAW,EAAG,QAAO;AAGlC,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AAEvE,MAAI,SAAS;AACb,aAAW,YAAY,QAAQ;AAC7B,UAAM,YAAY,yBAAyB,QAAQ;AACnD,aAAS,OAAO,MAAM,GAAG,SAAS,UAAU,IAAI,YAAY,OAAO,MAAM,SAAS,QAAQ;AAAA,EAC5F;AAEA,SAAO;AACT;AAKO,IAAM,YAAY;AAKlB,IAAM,SAAS;AAKf,SAAS,sBAAsB,SAAkC;AACtE,UAAQ,SAAS;AAAA,IACf,KAAK;AAAkB,aAAO;AAAA,IAC9B,KAAK;AAAgB,aAAO;AAAA,IAC5B,KAAK;AAAkB,aAAO;AAAA,IAC9B,KAAK;AAAgB,aAAO;AAAA,IAC5B,KAAK;AAAiB,aAAO;AAAA,IAC7B,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAgB,aAAO;AAAA,EAC9B;AACF;AAKO,SAAS,iBAAiB,MAA8D;AAC7F,QAAM,QAAQ;AACd,QAAM,YAA4D,CAAC;AACnE,MAAI;AAEJ,UAAQ,QAAQ,MAAM,KAAK,IAAI,OAAO,MAAM;AAC1C,cAAU,KAAK;AAAA,MACb,MAAM,MAAM,CAAC,EAAE,KAAK;AAAA,MACpB,cAAc,MAAM,CAAC,GAAG,KAAK;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAKO,SAAS,QACd,UACA,QACA,UAAqC,CAAC,GAC9B;AACR,QAAM,EAAE,cAAc,KAAK,IAAI;AAE/B,SAAO,SAAS;AAAA,IACd;AAAA,IACA,CAAC,OAAO,MAAM,iBAAiB;AAC7B,YAAM,cAAc,KAAK,KAAK;AAC9B,UAAI,eAAe,QAAQ;AACzB,eAAO,OAAO,WAAW;AAAA,MAC3B;AACA,UAAI,eAAe,iBAAiB,QAAW;AAC7C,eAAO,aAAa,KAAK;AAAA,MAC3B;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/variables/index.ts"],"sourcesContent":["/**\n * Variable Detection Utility\n * Detects common variable-like patterns in text that could be converted\n * to our supported format: ${variableName} or ${variableName:default}\n */\n\nexport interface DetectedVariable {\n original: string;\n name: string;\n defaultValue?: string;\n pattern: VariablePattern;\n startIndex: number;\n endIndex: number;\n}\n\nexport type VariablePattern = \n | \"double_bracket\" // [[name]] or [[ name ]]\n | \"double_curly\" // {{name}} or {{ name }}\n | \"single_bracket\" // [NAME] or [name]\n | \"single_curly\" // {NAME} or {name}\n | \"angle_bracket\" // <NAME> or <name>\n | \"percent\" // %NAME% or %name%\n | \"dollar_curly\"; // ${name} (already our format)\n\ninterface PatternConfig {\n pattern: VariablePattern;\n regex: RegExp;\n extractName: (match: RegExpExecArray) => string;\n extractDefault?: (match: RegExpExecArray) => string | undefined;\n}\n\n// Patterns to detect, ordered by specificity (more specific first)\nconst PATTERNS: PatternConfig[] = [\n // Double bracket: [[name]] or [[ name ]] or [[name: default]]\n {\n pattern: \"double_bracket\",\n regex: /\\[\\[\\s*([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?:\\s*:\\s*([^\\]]*?))?\\s*\\]\\]/g,\n extractName: (m) => m[1].trim(),\n extractDefault: (m) => m[2]?.trim(),\n },\n // Double curly: {{name}} or {{ name }} or {{name: default}}\n {\n pattern: \"double_curly\",\n regex: /\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?:\\s*:\\s*([^}]*?))?\\s*\\}\\}/g,\n extractName: (m) => m[1].trim(),\n extractDefault: (m) => m[2]?.trim(),\n },\n // Our supported format (to exclude from warnings)\n {\n pattern: \"dollar_curly\",\n regex: /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g,\n extractName: (m) => m[1].trim(),\n },\n // Single bracket with uppercase or placeholder-like: [NAME] or [Your Name]\n {\n pattern: \"single_bracket\",\n regex: /\\[([A-Z][A-Z0-9_\\s]*|[A-Za-z][a-zA-Z0-9_]*(?:\\s+[A-Za-z][a-zA-Z0-9_]*)*)\\]/g,\n extractName: (m) => m[1].trim(),\n },\n // Single curly with uppercase: {NAME} or {Your Name}\n {\n pattern: \"single_curly\",\n regex: /\\{([A-Z][A-Z0-9_\\s]*|[A-Za-z][a-zA-Z0-9_]*(?:\\s+[A-Za-z][a-zA-Z0-9_]*)*)\\}/g,\n extractName: (m) => m[1].trim(),\n },\n // Angle brackets: <NAME> or <name>\n {\n pattern: \"angle_bracket\",\n regex: /<([A-Z][A-Z0-9_\\s]*|[a-zA-Z_][a-zA-Z0-9_\\s]*)>/g,\n extractName: (m) => m[1].trim(),\n },\n // Percent signs: %NAME% or %name%\n {\n pattern: \"percent\",\n regex: /%([a-zA-Z_][a-zA-Z0-9_]*)%/g,\n extractName: (m) => m[1].trim(),\n },\n];\n\n// Common false positives to ignore\nconst FALSE_POSITIVES = new Set([\n // HTML/XML common tags\n \"div\", \"span\", \"p\", \"a\", \"br\", \"hr\", \"img\", \"input\", \"button\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"ul\", \"ol\", \"li\", \"table\",\n \"tr\", \"td\", \"th\", \"thead\", \"tbody\", \"form\", \"label\", \"select\",\n \"option\", \"textarea\", \"script\", \"style\", \"link\", \"meta\", \"head\",\n \"body\", \"html\", \"section\", \"article\", \"nav\", \"header\", \"footer\",\n \"main\", \"aside\", \"figure\", \"figcaption\", \"strong\", \"em\", \"code\",\n \"pre\", \"blockquote\", \"cite\", \"abbr\", \"address\", \"b\", \"i\", \"u\",\n // Common programming constructs\n \"if\", \"else\", \"for\", \"while\", \"switch\", \"case\", \"break\", \"return\",\n \"function\", \"class\", \"const\", \"let\", \"var\", \"import\", \"export\",\n \"default\", \"try\", \"catch\", \"finally\", \"throw\", \"new\", \"this\",\n \"null\", \"undefined\", \"true\", \"false\", \"typeof\", \"instanceof\",\n // JSON structure keywords (when in context)\n \"type\", \"id\", \"key\", \"value\", \"data\", \"items\", \"properties\",\n]);\n\n/**\n * Check if we're inside a JSON string context\n */\nfunction isInsideJsonString(text: string, index: number): boolean {\n let inString = false;\n for (let i = 0; i < index; i++) {\n if (text[i] === '\"' && (i === 0 || text[i - 1] !== '\\\\')) {\n inString = !inString;\n }\n }\n return inString;\n}\n\n/**\n * Detect variable-like patterns in text\n * Returns detected variables that are NOT in our supported format\n */\nexport function detectVariables(text: string): DetectedVariable[] {\n const detected: DetectedVariable[] = [];\n const seenRanges: Array<[number, number]> = [];\n \n // Track our supported format positions to exclude them\n const supportedVars = new Set<string>();\n const dollarCurlyPattern = /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g;\n let match: RegExpExecArray | null;\n \n while ((match = dollarCurlyPattern.exec(text)) !== null) {\n seenRanges.push([match.index, match.index + match[0].length]);\n supportedVars.add(match[0]);\n }\n \n // Check each pattern\n for (const config of PATTERNS) {\n // Skip our supported format pattern for detection\n if (config.pattern === \"dollar_curly\") continue;\n \n const regex = new RegExp(config.regex.source, config.regex.flags);\n \n while ((match = regex.exec(text)) !== null) {\n const startIndex = match.index;\n const endIndex = startIndex + match[0].length;\n \n // Check if this range overlaps with any already detected range\n const overlaps = seenRanges.some(\n ([start, end]) => \n (startIndex >= start && startIndex < end) ||\n (endIndex > start && endIndex <= end)\n );\n \n if (overlaps) continue;\n \n const name = config.extractName(match);\n \n // Skip false positives\n if (FALSE_POSITIVES.has(name.toLowerCase())) continue;\n \n // Skip very short names (likely not variables)\n if (name.length < 2) continue;\n \n // For angle brackets, be more strict\n if (config.pattern === \"angle_bracket\") {\n if (!/^[A-Z]/.test(name) && !name.includes(\" \")) continue;\n }\n \n // For single curly/bracket in JSON context, be more careful\n if (\n (config.pattern === \"single_curly\" || config.pattern === \"single_bracket\") &&\n isInsideJsonString(text, startIndex)\n ) {\n if (!/^[A-Z]/.test(name) && !name.includes(\" \")) continue;\n }\n \n const defaultValue = config.extractDefault?.(match);\n \n detected.push({\n original: match[0],\n name,\n defaultValue,\n pattern: config.pattern,\n startIndex,\n endIndex,\n });\n \n seenRanges.push([startIndex, endIndex]);\n }\n }\n \n // Sort by position and remove duplicates\n return detected\n .sort((a, b) => a.startIndex - b.startIndex)\n .filter((v, i, arr) => \n i === 0 || v.original !== arr[i - 1].original || v.startIndex !== arr[i - 1].startIndex\n );\n}\n\n/**\n * Convert a detected variable to our supported format\n */\nexport function convertToSupportedFormat(variable: DetectedVariable): string {\n // Normalize name: lowercase, replace spaces with underscores\n const normalizedName = variable.name\n .toLowerCase()\n .replace(/\\s+/g, \"_\")\n .replace(/[^a-z0-9_]/g, \"\");\n \n if (variable.defaultValue) {\n return `\\${${normalizedName}:${variable.defaultValue}}`;\n }\n \n return `\\${${normalizedName}}`;\n}\n\n/**\n * Convert all detected variables in text to our supported format\n */\nexport function convertAllVariables(text: string): string {\n const detected = detectVariables(text);\n \n if (detected.length === 0) return text;\n \n // Sort by position descending to replace from end to start\n const sorted = [...detected].sort((a, b) => b.startIndex - a.startIndex);\n \n let result = text;\n for (const variable of sorted) {\n const converted = convertToSupportedFormat(variable);\n result = result.slice(0, variable.startIndex) + converted + result.slice(variable.endIndex);\n }\n \n return result;\n}\n\n/**\n * Alias for convertAllVariables - normalizes all variable formats to ${var}\n */\nexport const normalize = convertAllVariables;\n\n/**\n * Alias for detectVariables\n */\nexport const detect = detectVariables;\n\n/**\n * Get a human-readable pattern description\n */\nexport function getPatternDescription(pattern: VariablePattern): string {\n switch (pattern) {\n case \"double_bracket\": return \"[[...]]\";\n case \"double_curly\": return \"{{...}}\";\n case \"single_bracket\": return \"[...]\";\n case \"single_curly\": return \"{...}\";\n case \"angle_bracket\": return \"<...>\";\n case \"percent\": return \"%...%\";\n case \"dollar_curly\": return \"${...}\";\n }\n}\n\n/**\n * Extract variables from our supported ${var} or ${var:default} format\n */\nexport function extractVariables(text: string): Array<{ name: string; defaultValue?: string }> {\n const regex = /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g;\n const variables: Array<{ name: string; defaultValue?: string }> = [];\n let match: RegExpExecArray | null;\n \n while ((match = regex.exec(text)) !== null) {\n variables.push({\n name: match[1].trim(),\n defaultValue: match[2]?.trim(),\n });\n }\n \n return variables;\n}\n\n/**\n * Compile a prompt template with variable values\n */\nexport function compile(\n template: string, \n values: Record<string, string>,\n options: { useDefaults?: boolean } = {}\n): string {\n const { useDefaults = true } = options;\n \n return template.replace(\n /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g,\n (match, name, defaultValue) => {\n const trimmedName = name.trim();\n if (trimmedName in values) {\n return values[trimmedName];\n }\n if (useDefaults && defaultValue !== undefined) {\n return defaultValue.trim();\n }\n return match; // Keep original if no value and no default\n }\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { D as DetectedVariable, V as VariablePattern, b as compile, a as convertAllVariables, c as convertToSupportedFormat, f as detect, d as detectVariables, e as extractVariables, g as getPatternDescription, n as normalize } from '../index-DOz8zcA0.
|
|
1
|
+
export { D as DetectedVariable, V as VariablePattern, b as compile, a as convertAllVariables, c as convertToSupportedFormat, f as detect, d as detectVariables, e as extractVariables, g as getPatternDescription, n as normalize } from '../index-DOz8zcA0.cjs';
|
package/dist/variables/index.js
CHANGED
|
@@ -1,35 +1,4 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
1
|
// src/variables/index.ts
|
|
21
|
-
var variables_exports = {};
|
|
22
|
-
__export(variables_exports, {
|
|
23
|
-
compile: () => compile,
|
|
24
|
-
convertAllVariables: () => convertAllVariables,
|
|
25
|
-
convertToSupportedFormat: () => convertToSupportedFormat,
|
|
26
|
-
detect: () => detect,
|
|
27
|
-
detectVariables: () => detectVariables,
|
|
28
|
-
extractVariables: () => extractVariables,
|
|
29
|
-
getPatternDescription: () => getPatternDescription,
|
|
30
|
-
normalize: () => normalize
|
|
31
|
-
});
|
|
32
|
-
module.exports = __toCommonJS(variables_exports);
|
|
33
2
|
var PATTERNS = [
|
|
34
3
|
// Double bracket: [[name]] or [[ name ]] or [[name: default]]
|
|
35
4
|
{
|
|
@@ -292,8 +261,7 @@ function compile(template, values, options = {}) {
|
|
|
292
261
|
}
|
|
293
262
|
);
|
|
294
263
|
}
|
|
295
|
-
|
|
296
|
-
0 && (module.exports = {
|
|
264
|
+
export {
|
|
297
265
|
compile,
|
|
298
266
|
convertAllVariables,
|
|
299
267
|
convertToSupportedFormat,
|
|
@@ -302,5 +270,5 @@ function compile(template, values, options = {}) {
|
|
|
302
270
|
extractVariables,
|
|
303
271
|
getPatternDescription,
|
|
304
272
|
normalize
|
|
305
|
-
}
|
|
273
|
+
};
|
|
306
274
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/variables/index.ts"],"sourcesContent":["/**\n * Variable Detection Utility\n * Detects common variable-like patterns in text that could be converted\n * to our supported format: ${variableName} or ${variableName:default}\n */\n\nexport interface DetectedVariable {\n original: string;\n name: string;\n defaultValue?: string;\n pattern: VariablePattern;\n startIndex: number;\n endIndex: number;\n}\n\nexport type VariablePattern = \n | \"double_bracket\" // [[name]] or [[ name ]]\n | \"double_curly\" // {{name}} or {{ name }}\n | \"single_bracket\" // [NAME] or [name]\n | \"single_curly\" // {NAME} or {name}\n | \"angle_bracket\" // <NAME> or <name>\n | \"percent\" // %NAME% or %name%\n | \"dollar_curly\"; // ${name} (already our format)\n\ninterface PatternConfig {\n pattern: VariablePattern;\n regex: RegExp;\n extractName: (match: RegExpExecArray) => string;\n extractDefault?: (match: RegExpExecArray) => string | undefined;\n}\n\n// Patterns to detect, ordered by specificity (more specific first)\nconst PATTERNS: PatternConfig[] = [\n // Double bracket: [[name]] or [[ name ]] or [[name: default]]\n {\n pattern: \"double_bracket\",\n regex: /\\[\\[\\s*([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?:\\s*:\\s*([^\\]]*?))?\\s*\\]\\]/g,\n extractName: (m) => m[1].trim(),\n extractDefault: (m) => m[2]?.trim(),\n },\n // Double curly: {{name}} or {{ name }} or {{name: default}}\n {\n pattern: \"double_curly\",\n regex: /\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?:\\s*:\\s*([^}]*?))?\\s*\\}\\}/g,\n extractName: (m) => m[1].trim(),\n extractDefault: (m) => m[2]?.trim(),\n },\n // Our supported format (to exclude from warnings)\n {\n pattern: \"dollar_curly\",\n regex: /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g,\n extractName: (m) => m[1].trim(),\n },\n // Single bracket with uppercase or placeholder-like: [NAME] or [Your Name]\n {\n pattern: \"single_bracket\",\n regex: /\\[([A-Z][A-Z0-9_\\s]*|[A-Za-z][a-zA-Z0-9_]*(?:\\s+[A-Za-z][a-zA-Z0-9_]*)*)\\]/g,\n extractName: (m) => m[1].trim(),\n },\n // Single curly with uppercase: {NAME} or {Your Name}\n {\n pattern: \"single_curly\",\n regex: /\\{([A-Z][A-Z0-9_\\s]*|[A-Za-z][a-zA-Z0-9_]*(?:\\s+[A-Za-z][a-zA-Z0-9_]*)*)\\}/g,\n extractName: (m) => m[1].trim(),\n },\n // Angle brackets: <NAME> or <name>\n {\n pattern: \"angle_bracket\",\n regex: /<([A-Z][A-Z0-9_\\s]*|[a-zA-Z_][a-zA-Z0-9_\\s]*)>/g,\n extractName: (m) => m[1].trim(),\n },\n // Percent signs: %NAME% or %name%\n {\n pattern: \"percent\",\n regex: /%([a-zA-Z_][a-zA-Z0-9_]*)%/g,\n extractName: (m) => m[1].trim(),\n },\n];\n\n// Common false positives to ignore\nconst FALSE_POSITIVES = new Set([\n // HTML/XML common tags\n \"div\", \"span\", \"p\", \"a\", \"br\", \"hr\", \"img\", \"input\", \"button\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"ul\", \"ol\", \"li\", \"table\",\n \"tr\", \"td\", \"th\", \"thead\", \"tbody\", \"form\", \"label\", \"select\",\n \"option\", \"textarea\", \"script\", \"style\", \"link\", \"meta\", \"head\",\n \"body\", \"html\", \"section\", \"article\", \"nav\", \"header\", \"footer\",\n \"main\", \"aside\", \"figure\", \"figcaption\", \"strong\", \"em\", \"code\",\n \"pre\", \"blockquote\", \"cite\", \"abbr\", \"address\", \"b\", \"i\", \"u\",\n // Common programming constructs\n \"if\", \"else\", \"for\", \"while\", \"switch\", \"case\", \"break\", \"return\",\n \"function\", \"class\", \"const\", \"let\", \"var\", \"import\", \"export\",\n \"default\", \"try\", \"catch\", \"finally\", \"throw\", \"new\", \"this\",\n \"null\", \"undefined\", \"true\", \"false\", \"typeof\", \"instanceof\",\n // JSON structure keywords (when in context)\n \"type\", \"id\", \"key\", \"value\", \"data\", \"items\", \"properties\",\n]);\n\n/**\n * Check if we're inside a JSON string context\n */\nfunction isInsideJsonString(text: string, index: number): boolean {\n let inString = false;\n for (let i = 0; i < index; i++) {\n if (text[i] === '\"' && (i === 0 || text[i - 1] !== '\\\\')) {\n inString = !inString;\n }\n }\n return inString;\n}\n\n/**\n * Detect variable-like patterns in text\n * Returns detected variables that are NOT in our supported format\n */\nexport function detectVariables(text: string): DetectedVariable[] {\n const detected: DetectedVariable[] = [];\n const seenRanges: Array<[number, number]> = [];\n \n // Track our supported format positions to exclude them\n const supportedVars = new Set<string>();\n const dollarCurlyPattern = /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g;\n let match: RegExpExecArray | null;\n \n while ((match = dollarCurlyPattern.exec(text)) !== null) {\n seenRanges.push([match.index, match.index + match[0].length]);\n supportedVars.add(match[0]);\n }\n \n // Check each pattern\n for (const config of PATTERNS) {\n // Skip our supported format pattern for detection\n if (config.pattern === \"dollar_curly\") continue;\n \n const regex = new RegExp(config.regex.source, config.regex.flags);\n \n while ((match = regex.exec(text)) !== null) {\n const startIndex = match.index;\n const endIndex = startIndex + match[0].length;\n \n // Check if this range overlaps with any already detected range\n const overlaps = seenRanges.some(\n ([start, end]) => \n (startIndex >= start && startIndex < end) ||\n (endIndex > start && endIndex <= end)\n );\n \n if (overlaps) continue;\n \n const name = config.extractName(match);\n \n // Skip false positives\n if (FALSE_POSITIVES.has(name.toLowerCase())) continue;\n \n // Skip very short names (likely not variables)\n if (name.length < 2) continue;\n \n // For angle brackets, be more strict\n if (config.pattern === \"angle_bracket\") {\n if (!/^[A-Z]/.test(name) && !name.includes(\" \")) continue;\n }\n \n // For single curly/bracket in JSON context, be more careful\n if (\n (config.pattern === \"single_curly\" || config.pattern === \"single_bracket\") &&\n isInsideJsonString(text, startIndex)\n ) {\n if (!/^[A-Z]/.test(name) && !name.includes(\" \")) continue;\n }\n \n const defaultValue = config.extractDefault?.(match);\n \n detected.push({\n original: match[0],\n name,\n defaultValue,\n pattern: config.pattern,\n startIndex,\n endIndex,\n });\n \n seenRanges.push([startIndex, endIndex]);\n }\n }\n \n // Sort by position and remove duplicates\n return detected\n .sort((a, b) => a.startIndex - b.startIndex)\n .filter((v, i, arr) => \n i === 0 || v.original !== arr[i - 1].original || v.startIndex !== arr[i - 1].startIndex\n );\n}\n\n/**\n * Convert a detected variable to our supported format\n */\nexport function convertToSupportedFormat(variable: DetectedVariable): string {\n // Normalize name: lowercase, replace spaces with underscores\n const normalizedName = variable.name\n .toLowerCase()\n .replace(/\\s+/g, \"_\")\n .replace(/[^a-z0-9_]/g, \"\");\n \n if (variable.defaultValue) {\n return `\\${${normalizedName}:${variable.defaultValue}}`;\n }\n \n return `\\${${normalizedName}}`;\n}\n\n/**\n * Convert all detected variables in text to our supported format\n */\nexport function convertAllVariables(text: string): string {\n const detected = detectVariables(text);\n \n if (detected.length === 0) return text;\n \n // Sort by position descending to replace from end to start\n const sorted = [...detected].sort((a, b) => b.startIndex - a.startIndex);\n \n let result = text;\n for (const variable of sorted) {\n const converted = convertToSupportedFormat(variable);\n result = result.slice(0, variable.startIndex) + converted + result.slice(variable.endIndex);\n }\n \n return result;\n}\n\n/**\n * Alias for convertAllVariables - normalizes all variable formats to ${var}\n */\nexport const normalize = convertAllVariables;\n\n/**\n * Alias for detectVariables\n */\nexport const detect = detectVariables;\n\n/**\n * Get a human-readable pattern description\n */\nexport function getPatternDescription(pattern: VariablePattern): string {\n switch (pattern) {\n case \"double_bracket\": return \"[[...]]\";\n case \"double_curly\": return \"{{...}}\";\n case \"single_bracket\": return \"[...]\";\n case \"single_curly\": return \"{...}\";\n case \"angle_bracket\": return \"<...>\";\n case \"percent\": return \"%...%\";\n case \"dollar_curly\": return \"${...}\";\n }\n}\n\n/**\n * Extract variables from our supported ${var} or ${var:default} format\n */\nexport function extractVariables(text: string): Array<{ name: string; defaultValue?: string }> {\n const regex = /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g;\n const variables: Array<{ name: string; defaultValue?: string }> = [];\n let match: RegExpExecArray | null;\n \n while ((match = regex.exec(text)) !== null) {\n variables.push({\n name: match[1].trim(),\n defaultValue: match[2]?.trim(),\n });\n }\n \n return variables;\n}\n\n/**\n * Compile a prompt template with variable values\n */\nexport function compile(\n template: string, \n values: Record<string, string>,\n options: { useDefaults?: boolean } = {}\n): string {\n const { useDefaults = true } = options;\n \n return template.replace(\n /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g,\n (match, name, defaultValue) => {\n const trimmedName = name.trim();\n if (trimmedName in values) {\n return values[trimmedName];\n }\n if (useDefaults && defaultValue !== undefined) {\n return defaultValue.trim();\n }\n return match; // Keep original if no value and no default\n }\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/variables/index.ts"],"sourcesContent":["/**\n * Variable Detection Utility\n * Detects common variable-like patterns in text that could be converted\n * to our supported format: ${variableName} or ${variableName:default}\n */\n\nexport interface DetectedVariable {\n original: string;\n name: string;\n defaultValue?: string;\n pattern: VariablePattern;\n startIndex: number;\n endIndex: number;\n}\n\nexport type VariablePattern = \n | \"double_bracket\" // [[name]] or [[ name ]]\n | \"double_curly\" // {{name}} or {{ name }}\n | \"single_bracket\" // [NAME] or [name]\n | \"single_curly\" // {NAME} or {name}\n | \"angle_bracket\" // <NAME> or <name>\n | \"percent\" // %NAME% or %name%\n | \"dollar_curly\"; // ${name} (already our format)\n\ninterface PatternConfig {\n pattern: VariablePattern;\n regex: RegExp;\n extractName: (match: RegExpExecArray) => string;\n extractDefault?: (match: RegExpExecArray) => string | undefined;\n}\n\n// Patterns to detect, ordered by specificity (more specific first)\nconst PATTERNS: PatternConfig[] = [\n // Double bracket: [[name]] or [[ name ]] or [[name: default]]\n {\n pattern: \"double_bracket\",\n regex: /\\[\\[\\s*([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?:\\s*:\\s*([^\\]]*?))?\\s*\\]\\]/g,\n extractName: (m) => m[1].trim(),\n extractDefault: (m) => m[2]?.trim(),\n },\n // Double curly: {{name}} or {{ name }} or {{name: default}}\n {\n pattern: \"double_curly\",\n regex: /\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?:\\s*:\\s*([^}]*?))?\\s*\\}\\}/g,\n extractName: (m) => m[1].trim(),\n extractDefault: (m) => m[2]?.trim(),\n },\n // Our supported format (to exclude from warnings)\n {\n pattern: \"dollar_curly\",\n regex: /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g,\n extractName: (m) => m[1].trim(),\n },\n // Single bracket with uppercase or placeholder-like: [NAME] or [Your Name]\n {\n pattern: \"single_bracket\",\n regex: /\\[([A-Z][A-Z0-9_\\s]*|[A-Za-z][a-zA-Z0-9_]*(?:\\s+[A-Za-z][a-zA-Z0-9_]*)*)\\]/g,\n extractName: (m) => m[1].trim(),\n },\n // Single curly with uppercase: {NAME} or {Your Name}\n {\n pattern: \"single_curly\",\n regex: /\\{([A-Z][A-Z0-9_\\s]*|[A-Za-z][a-zA-Z0-9_]*(?:\\s+[A-Za-z][a-zA-Z0-9_]*)*)\\}/g,\n extractName: (m) => m[1].trim(),\n },\n // Angle brackets: <NAME> or <name>\n {\n pattern: \"angle_bracket\",\n regex: /<([A-Z][A-Z0-9_\\s]*|[a-zA-Z_][a-zA-Z0-9_\\s]*)>/g,\n extractName: (m) => m[1].trim(),\n },\n // Percent signs: %NAME% or %name%\n {\n pattern: \"percent\",\n regex: /%([a-zA-Z_][a-zA-Z0-9_]*)%/g,\n extractName: (m) => m[1].trim(),\n },\n];\n\n// Common false positives to ignore\nconst FALSE_POSITIVES = new Set([\n // HTML/XML common tags\n \"div\", \"span\", \"p\", \"a\", \"br\", \"hr\", \"img\", \"input\", \"button\",\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"ul\", \"ol\", \"li\", \"table\",\n \"tr\", \"td\", \"th\", \"thead\", \"tbody\", \"form\", \"label\", \"select\",\n \"option\", \"textarea\", \"script\", \"style\", \"link\", \"meta\", \"head\",\n \"body\", \"html\", \"section\", \"article\", \"nav\", \"header\", \"footer\",\n \"main\", \"aside\", \"figure\", \"figcaption\", \"strong\", \"em\", \"code\",\n \"pre\", \"blockquote\", \"cite\", \"abbr\", \"address\", \"b\", \"i\", \"u\",\n // Common programming constructs\n \"if\", \"else\", \"for\", \"while\", \"switch\", \"case\", \"break\", \"return\",\n \"function\", \"class\", \"const\", \"let\", \"var\", \"import\", \"export\",\n \"default\", \"try\", \"catch\", \"finally\", \"throw\", \"new\", \"this\",\n \"null\", \"undefined\", \"true\", \"false\", \"typeof\", \"instanceof\",\n // JSON structure keywords (when in context)\n \"type\", \"id\", \"key\", \"value\", \"data\", \"items\", \"properties\",\n]);\n\n/**\n * Check if we're inside a JSON string context\n */\nfunction isInsideJsonString(text: string, index: number): boolean {\n let inString = false;\n for (let i = 0; i < index; i++) {\n if (text[i] === '\"' && (i === 0 || text[i - 1] !== '\\\\')) {\n inString = !inString;\n }\n }\n return inString;\n}\n\n/**\n * Detect variable-like patterns in text\n * Returns detected variables that are NOT in our supported format\n */\nexport function detectVariables(text: string): DetectedVariable[] {\n const detected: DetectedVariable[] = [];\n const seenRanges: Array<[number, number]> = [];\n \n // Track our supported format positions to exclude them\n const supportedVars = new Set<string>();\n const dollarCurlyPattern = /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g;\n let match: RegExpExecArray | null;\n \n while ((match = dollarCurlyPattern.exec(text)) !== null) {\n seenRanges.push([match.index, match.index + match[0].length]);\n supportedVars.add(match[0]);\n }\n \n // Check each pattern\n for (const config of PATTERNS) {\n // Skip our supported format pattern for detection\n if (config.pattern === \"dollar_curly\") continue;\n \n const regex = new RegExp(config.regex.source, config.regex.flags);\n \n while ((match = regex.exec(text)) !== null) {\n const startIndex = match.index;\n const endIndex = startIndex + match[0].length;\n \n // Check if this range overlaps with any already detected range\n const overlaps = seenRanges.some(\n ([start, end]) => \n (startIndex >= start && startIndex < end) ||\n (endIndex > start && endIndex <= end)\n );\n \n if (overlaps) continue;\n \n const name = config.extractName(match);\n \n // Skip false positives\n if (FALSE_POSITIVES.has(name.toLowerCase())) continue;\n \n // Skip very short names (likely not variables)\n if (name.length < 2) continue;\n \n // For angle brackets, be more strict\n if (config.pattern === \"angle_bracket\") {\n if (!/^[A-Z]/.test(name) && !name.includes(\" \")) continue;\n }\n \n // For single curly/bracket in JSON context, be more careful\n if (\n (config.pattern === \"single_curly\" || config.pattern === \"single_bracket\") &&\n isInsideJsonString(text, startIndex)\n ) {\n if (!/^[A-Z]/.test(name) && !name.includes(\" \")) continue;\n }\n \n const defaultValue = config.extractDefault?.(match);\n \n detected.push({\n original: match[0],\n name,\n defaultValue,\n pattern: config.pattern,\n startIndex,\n endIndex,\n });\n \n seenRanges.push([startIndex, endIndex]);\n }\n }\n \n // Sort by position and remove duplicates\n return detected\n .sort((a, b) => a.startIndex - b.startIndex)\n .filter((v, i, arr) => \n i === 0 || v.original !== arr[i - 1].original || v.startIndex !== arr[i - 1].startIndex\n );\n}\n\n/**\n * Convert a detected variable to our supported format\n */\nexport function convertToSupportedFormat(variable: DetectedVariable): string {\n // Normalize name: lowercase, replace spaces with underscores\n const normalizedName = variable.name\n .toLowerCase()\n .replace(/\\s+/g, \"_\")\n .replace(/[^a-z0-9_]/g, \"\");\n \n if (variable.defaultValue) {\n return `\\${${normalizedName}:${variable.defaultValue}}`;\n }\n \n return `\\${${normalizedName}}`;\n}\n\n/**\n * Convert all detected variables in text to our supported format\n */\nexport function convertAllVariables(text: string): string {\n const detected = detectVariables(text);\n \n if (detected.length === 0) return text;\n \n // Sort by position descending to replace from end to start\n const sorted = [...detected].sort((a, b) => b.startIndex - a.startIndex);\n \n let result = text;\n for (const variable of sorted) {\n const converted = convertToSupportedFormat(variable);\n result = result.slice(0, variable.startIndex) + converted + result.slice(variable.endIndex);\n }\n \n return result;\n}\n\n/**\n * Alias for convertAllVariables - normalizes all variable formats to ${var}\n */\nexport const normalize = convertAllVariables;\n\n/**\n * Alias for detectVariables\n */\nexport const detect = detectVariables;\n\n/**\n * Get a human-readable pattern description\n */\nexport function getPatternDescription(pattern: VariablePattern): string {\n switch (pattern) {\n case \"double_bracket\": return \"[[...]]\";\n case \"double_curly\": return \"{{...}}\";\n case \"single_bracket\": return \"[...]\";\n case \"single_curly\": return \"{...}\";\n case \"angle_bracket\": return \"<...>\";\n case \"percent\": return \"%...%\";\n case \"dollar_curly\": return \"${...}\";\n }\n}\n\n/**\n * Extract variables from our supported ${var} or ${var:default} format\n */\nexport function extractVariables(text: string): Array<{ name: string; defaultValue?: string }> {\n const regex = /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g;\n const variables: Array<{ name: string; defaultValue?: string }> = [];\n let match: RegExpExecArray | null;\n \n while ((match = regex.exec(text)) !== null) {\n variables.push({\n name: match[1].trim(),\n defaultValue: match[2]?.trim(),\n });\n }\n \n return variables;\n}\n\n/**\n * Compile a prompt template with variable values\n */\nexport function compile(\n template: string, \n values: Record<string, string>,\n options: { useDefaults?: boolean } = {}\n): string {\n const { useDefaults = true } = options;\n \n return template.replace(\n /\\$\\{([a-zA-Z_][a-zA-Z0-9_\\s]*?)(?::([^}]*))?\\}/g,\n (match, name, defaultValue) => {\n const trimmedName = name.trim();\n if (trimmedName in values) {\n return values[trimmedName];\n }\n if (useDefaults && defaultValue !== undefined) {\n return defaultValue.trim();\n }\n return match; // Keep original if no value and no default\n }\n );\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prompts.chat",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "Developer toolkit for AI prompts - build, validate, parse, and connect to prompts.chat",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "./dist/index.js",
|
|
6
7
|
"module": "./dist/index.mjs",
|
|
7
8
|
"types": "./dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"prompts-chat": "./bin/cli.js",
|
|
11
|
+
"prompts.chat": "./bin/cli.js"
|
|
12
|
+
},
|
|
8
13
|
"exports": {
|
|
9
14
|
".": {
|
|
10
15
|
"types": "./dist/index.d.ts",
|
|
@@ -75,8 +80,20 @@
|
|
|
75
80
|
"docs": "npx ts-node scripts/generate-docs.ts",
|
|
76
81
|
"docs:generate": "npx tsx scripts/generate-docs.ts"
|
|
77
82
|
},
|
|
83
|
+
"dependencies": {
|
|
84
|
+
"ink": "^5.1.0",
|
|
85
|
+
"ink-text-input": "^6.0.0",
|
|
86
|
+
"ink-spinner": "^5.0.0",
|
|
87
|
+
"ink-select-input": "^6.0.0",
|
|
88
|
+
"react": "^18.3.1",
|
|
89
|
+
"clipboardy": "^4.0.0",
|
|
90
|
+
"meow": "^13.2.0",
|
|
91
|
+
"open": "^10.1.0",
|
|
92
|
+
"terminal-image": "^3.0.0"
|
|
93
|
+
},
|
|
78
94
|
"devDependencies": {
|
|
79
95
|
"@types/node": "^20",
|
|
96
|
+
"@types/react": "^18.3.0",
|
|
80
97
|
"tsup": "^8.0.0",
|
|
81
98
|
"typescript": "^5",
|
|
82
99
|
"vitest": "^4.0.16"
|