@formfeed/mcp 0.1.0 → 0.2.0
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/formfeed-mcp.mjs +410 -53
- package/package.json +1 -1
package/bin/formfeed-mcp.mjs
CHANGED
|
@@ -1155,16 +1155,16 @@ var require_numeric_data = __commonJS({
|
|
|
1155
1155
|
return NumericData.getBitsLength(this.data.length);
|
|
1156
1156
|
};
|
|
1157
1157
|
NumericData.prototype.write = function write(bitBuffer) {
|
|
1158
|
-
let i,
|
|
1158
|
+
let i, group2, value;
|
|
1159
1159
|
for (i = 0; i + 3 <= this.data.length; i += 3) {
|
|
1160
|
-
|
|
1161
|
-
value = parseInt(
|
|
1160
|
+
group2 = this.data.substr(i, 3);
|
|
1161
|
+
value = parseInt(group2, 10);
|
|
1162
1162
|
bitBuffer.put(value, 10);
|
|
1163
1163
|
}
|
|
1164
1164
|
const remainingNum = this.data.length - i;
|
|
1165
1165
|
if (remainingNum > 0) {
|
|
1166
|
-
|
|
1167
|
-
value = parseInt(
|
|
1166
|
+
group2 = this.data.substr(i);
|
|
1167
|
+
value = parseInt(group2, 10);
|
|
1168
1168
|
bitBuffer.put(value, remainingNum * 3 + 1);
|
|
1169
1169
|
}
|
|
1170
1170
|
};
|
|
@@ -20735,14 +20735,14 @@ var require_liquid_node = __commonJS({
|
|
|
20735
20735
|
constructor(token, remainTokens, liquid) {
|
|
20736
20736
|
super(token, remainTokens, liquid);
|
|
20737
20737
|
this.candidates = [];
|
|
20738
|
-
const
|
|
20738
|
+
const group2 = this.tokenizer.readValue();
|
|
20739
20739
|
this.tokenizer.skipBlank();
|
|
20740
|
-
if (
|
|
20740
|
+
if (group2) {
|
|
20741
20741
|
if (this.tokenizer.peek() === ":") {
|
|
20742
|
-
this.group =
|
|
20742
|
+
this.group = group2;
|
|
20743
20743
|
this.tokenizer.advance();
|
|
20744
20744
|
} else
|
|
20745
|
-
this.candidates.push(
|
|
20745
|
+
this.candidates.push(group2);
|
|
20746
20746
|
}
|
|
20747
20747
|
while (!this.tokenizer.end()) {
|
|
20748
20748
|
const value = this.tokenizer.readValue();
|
|
@@ -20753,8 +20753,8 @@ var require_liquid_node = __commonJS({
|
|
|
20753
20753
|
this.tokenizer.assert(this.candidates.length, () => `empty candidates: "${token.getText()}"`);
|
|
20754
20754
|
}
|
|
20755
20755
|
*render(ctx, emitter) {
|
|
20756
|
-
const
|
|
20757
|
-
const fingerprint = `cycle:${
|
|
20756
|
+
const group2 = yield evalToken(this.group, ctx);
|
|
20757
|
+
const fingerprint = `cycle:${group2}:` + this.candidates.join(",");
|
|
20758
20758
|
const groups = ctx.getRegister("cycle", {});
|
|
20759
20759
|
let idx = groups[fingerprint];
|
|
20760
20760
|
if (idx === void 0) {
|
|
@@ -77815,7 +77815,7 @@ var formatHelpers = [
|
|
|
77815
77815
|
name: "asset",
|
|
77816
77816
|
doc: {
|
|
77817
77817
|
signature: "asset(name)",
|
|
77818
|
-
description: "URL of a workspace
|
|
77818
|
+
description: "URL of a file in the workspace library (logo, background) on the CDN. Upload it on the Files page or with `POST /files` and use the name it has there; relative image paths resolve against the same library.",
|
|
77819
77819
|
example: `<img src="{{ asset('logo.png') }}">`,
|
|
77820
77820
|
category: "document"
|
|
77821
77821
|
},
|
|
@@ -78308,6 +78308,12 @@ function defaultHelpers() {
|
|
|
78308
78308
|
// packages/engine/src/lib/engines/handlebars.ts
|
|
78309
78309
|
var import_handlebars = __toESM(require_lib2());
|
|
78310
78310
|
|
|
78311
|
+
// packages/engine/src/lib/unavailable.ts
|
|
78312
|
+
var UNAVAILABLE = {};
|
|
78313
|
+
function unavailableHelper(name) {
|
|
78314
|
+
return UNAVAILABLE[name];
|
|
78315
|
+
}
|
|
78316
|
+
|
|
78311
78317
|
// packages/engine/src/lib/analysis/tags.ts
|
|
78312
78318
|
function rangeAt(line, column, length) {
|
|
78313
78319
|
return {
|
|
@@ -78487,7 +78493,10 @@ function missingPathDiagnostics(variables, sampleData, loopSources, builtinRoots
|
|
|
78487
78493
|
const root = v2.path[0];
|
|
78488
78494
|
if (!root || builtinRoots4.has(root)) continue;
|
|
78489
78495
|
let path = v2.path;
|
|
78490
|
-
if (
|
|
78496
|
+
if (v2.source !== void 0) {
|
|
78497
|
+
if (!v2.source) continue;
|
|
78498
|
+
path = [...v2.source, ...v2.path.slice(1)];
|
|
78499
|
+
} else if (loopSources.has(root)) {
|
|
78491
78500
|
const source = loopSources.get(root);
|
|
78492
78501
|
if (!source) continue;
|
|
78493
78502
|
path = [...source, ...v2.path.slice(1)];
|
|
@@ -78746,6 +78755,13 @@ function analyzeHandlebars(source, opts = {}) {
|
|
|
78746
78755
|
range: f2.range,
|
|
78747
78756
|
fix: { title: `Rename to ${preferred}`, replacement: preferred }
|
|
78748
78757
|
});
|
|
78758
|
+
} else if (unavailableHelper(f2.name)) {
|
|
78759
|
+
diagnostics.push({
|
|
78760
|
+
severity: "warning",
|
|
78761
|
+
code: "unavailable-helper",
|
|
78762
|
+
message: unavailableHelper(f2.name),
|
|
78763
|
+
range: f2.range
|
|
78764
|
+
});
|
|
78749
78765
|
} else if (!f2.known) {
|
|
78750
78766
|
diagnostics.push({
|
|
78751
78767
|
severity: "error",
|
|
@@ -78854,6 +78870,151 @@ var handlebarsEngine = {
|
|
|
78854
78870
|
|
|
78855
78871
|
// packages/engine/src/lib/engines/jinja2.ts
|
|
78856
78872
|
var import_nunjucks = __toESM(require_nunjucks());
|
|
78873
|
+
|
|
78874
|
+
// packages/engine/src/lib/engines/python-format.ts
|
|
78875
|
+
var SPEC = /^(?:([\s\S])?([<>=^]))?([+\- ])?(#)?(0)?(\d+)?([,_])?(?:\.(\d+))?([bcdeEfFgGnosxX%])?$/;
|
|
78876
|
+
function group(digits, separator) {
|
|
78877
|
+
return digits.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
|
|
78878
|
+
}
|
|
78879
|
+
function pythonExponent(text2) {
|
|
78880
|
+
return text2.replace(/e([+-])(\d)$/i, (m2, sign, digit) => `${m2[0]}${sign}0${digit}`);
|
|
78881
|
+
}
|
|
78882
|
+
function formatNumber(value, type, precision, alternate) {
|
|
78883
|
+
if (!Number.isFinite(value)) return Number.isNaN(value) ? "nan" : "inf";
|
|
78884
|
+
const abs = Math.abs(value);
|
|
78885
|
+
switch (type) {
|
|
78886
|
+
case "f":
|
|
78887
|
+
case "F":
|
|
78888
|
+
return abs.toFixed(precision ?? 6);
|
|
78889
|
+
case "%":
|
|
78890
|
+
return `${(abs * 100).toFixed(precision ?? 6)}%`;
|
|
78891
|
+
case "e":
|
|
78892
|
+
case "E": {
|
|
78893
|
+
const text2 = pythonExponent(abs.toExponential(precision ?? 6));
|
|
78894
|
+
return type === "E" ? text2.toUpperCase() : text2;
|
|
78895
|
+
}
|
|
78896
|
+
case "g":
|
|
78897
|
+
case "G": {
|
|
78898
|
+
const p = precision === 0 ? 1 : precision ?? 6;
|
|
78899
|
+
const exp = abs === 0 ? 0 : Math.floor(Math.log10(abs));
|
|
78900
|
+
let text2 = exp < -4 || exp >= p ? pythonExponent(abs.toExponential(p - 1)) : abs.toFixed(Math.max(0, p - 1 - exp));
|
|
78901
|
+
if (!alternate) {
|
|
78902
|
+
const [mantissa = "", exponent] = text2.split("e");
|
|
78903
|
+
const trimmed = mantissa.includes(".") ? mantissa.replace(/0+$/, "").replace(/\.$/, "") : mantissa;
|
|
78904
|
+
text2 = exponent === void 0 ? trimmed : `${trimmed}e${exponent}`;
|
|
78905
|
+
}
|
|
78906
|
+
return type === "G" ? text2.toUpperCase() : text2;
|
|
78907
|
+
}
|
|
78908
|
+
case "d":
|
|
78909
|
+
case "n":
|
|
78910
|
+
return String(Math.trunc(abs));
|
|
78911
|
+
case "b":
|
|
78912
|
+
return (alternate ? "0b" : "") + Math.trunc(abs).toString(2);
|
|
78913
|
+
case "o":
|
|
78914
|
+
return (alternate ? "0o" : "") + Math.trunc(abs).toString(8);
|
|
78915
|
+
case "x":
|
|
78916
|
+
return (alternate ? "0x" : "") + Math.trunc(abs).toString(16);
|
|
78917
|
+
case "X":
|
|
78918
|
+
return (alternate ? "0X" : "") + Math.trunc(abs).toString(16).toUpperCase();
|
|
78919
|
+
default:
|
|
78920
|
+
return precision === void 0 ? String(abs) : formatNumber(abs, "g", precision, alternate);
|
|
78921
|
+
}
|
|
78922
|
+
}
|
|
78923
|
+
function formatValue(value, spec) {
|
|
78924
|
+
const m2 = SPEC.exec(spec);
|
|
78925
|
+
if (!m2) return String(value ?? "");
|
|
78926
|
+
const [, fillChar, alignChar, sign, alt, zero, widthText, grouping, precisionText, type = ""] = m2;
|
|
78927
|
+
const precision = precisionText === void 0 ? void 0 : Number(precisionText);
|
|
78928
|
+
const width = widthText === void 0 ? 0 : Number(widthText);
|
|
78929
|
+
const numericType = /[bdeEfFgGnoxX%]/.test(type);
|
|
78930
|
+
const asNumber = typeof value === "number" ? value : typeof value === "boolean" ? Number(value) : numericType && value !== null && value !== void 0 && String(value).trim() !== "" && Number.isFinite(Number(value)) ? Number(value) : void 0;
|
|
78931
|
+
let body;
|
|
78932
|
+
let prefix = "";
|
|
78933
|
+
if (asNumber !== void 0 && type !== "s" && type !== "c") {
|
|
78934
|
+
body = formatNumber(asNumber, type, precision, Boolean(alt));
|
|
78935
|
+
if (grouping) {
|
|
78936
|
+
const [int = "", ...rest] = body.split(".");
|
|
78937
|
+
const radix = /^0[box]/i.exec(int)?.[0] ?? "";
|
|
78938
|
+
body = radix + group(int.slice(radix.length), grouping) + (rest.length ? `.${rest.join(".")}` : "");
|
|
78939
|
+
}
|
|
78940
|
+
const negative = asNumber < 0 || Object.is(asNumber, -0);
|
|
78941
|
+
prefix = negative ? "-" : sign === "+" ? "+" : sign === " " ? " " : "";
|
|
78942
|
+
} else if (type === "c" && asNumber !== void 0) {
|
|
78943
|
+
body = String.fromCodePoint(asNumber);
|
|
78944
|
+
} else {
|
|
78945
|
+
body = String(value ?? "None");
|
|
78946
|
+
if (precision !== void 0 && !numericType) body = body.slice(0, precision);
|
|
78947
|
+
}
|
|
78948
|
+
const isNumber = asNumber !== void 0 && type !== "s";
|
|
78949
|
+
const align = alignChar ?? (zero && isNumber ? "=" : isNumber ? ">" : "<");
|
|
78950
|
+
const fill = fillChar ?? (zero && !alignChar ? "0" : " ");
|
|
78951
|
+
const pad = Math.max(0, width - prefix.length - body.length);
|
|
78952
|
+
switch (align) {
|
|
78953
|
+
case "<":
|
|
78954
|
+
return prefix + body + fill.repeat(pad);
|
|
78955
|
+
case "^":
|
|
78956
|
+
return fill.repeat(Math.floor(pad / 2)) + prefix + body + fill.repeat(Math.ceil(pad / 2));
|
|
78957
|
+
case "=":
|
|
78958
|
+
return prefix + fill.repeat(pad) + body;
|
|
78959
|
+
default:
|
|
78960
|
+
return fill.repeat(pad) + prefix + body;
|
|
78961
|
+
}
|
|
78962
|
+
}
|
|
78963
|
+
function lookupField(name, positional, named, next) {
|
|
78964
|
+
const [head = "", ...rest] = name.split(/(?=[.[])/);
|
|
78965
|
+
let value = head === "" ? positional[next()] : /^\d+$/.test(head) ? positional[Number(head)] : named[head];
|
|
78966
|
+
for (const part of rest) {
|
|
78967
|
+
const key = part.startsWith("[") ? part.slice(1, -1) : part.slice(1);
|
|
78968
|
+
value = value !== null && typeof value === "object" ? value[Array.isArray(value) && /^\d+$/.test(key) ? Number(key) : key] : void 0;
|
|
78969
|
+
}
|
|
78970
|
+
return value;
|
|
78971
|
+
}
|
|
78972
|
+
function pythonFormat(template, positional, named = {}) {
|
|
78973
|
+
let auto = 0;
|
|
78974
|
+
const next = () => auto++;
|
|
78975
|
+
const render = (text2) => {
|
|
78976
|
+
let out = "";
|
|
78977
|
+
for (let i = 0; i < text2.length; i++) {
|
|
78978
|
+
const ch = text2[i];
|
|
78979
|
+
if (ch === "}") {
|
|
78980
|
+
out += "}";
|
|
78981
|
+
if (text2[i + 1] === "}") i++;
|
|
78982
|
+
continue;
|
|
78983
|
+
}
|
|
78984
|
+
if (ch !== "{") {
|
|
78985
|
+
out += ch;
|
|
78986
|
+
continue;
|
|
78987
|
+
}
|
|
78988
|
+
if (text2[i + 1] === "{") {
|
|
78989
|
+
out += "{";
|
|
78990
|
+
i++;
|
|
78991
|
+
continue;
|
|
78992
|
+
}
|
|
78993
|
+
let depth = 1;
|
|
78994
|
+
let j2 = i + 1;
|
|
78995
|
+
for (; j2 < text2.length && depth > 0; j2++) {
|
|
78996
|
+
if (text2[j2] === "{") depth++;
|
|
78997
|
+
else if (text2[j2] === "}") depth--;
|
|
78998
|
+
}
|
|
78999
|
+
if (depth > 0) {
|
|
79000
|
+
out += text2.slice(i);
|
|
79001
|
+
break;
|
|
79002
|
+
}
|
|
79003
|
+
const field = text2.slice(i + 1, j2 - 1);
|
|
79004
|
+
const colon = field.indexOf(":");
|
|
79005
|
+
const head = colon < 0 ? field : field.slice(0, colon);
|
|
79006
|
+
const name = head.replace(/![rsa]$/, "");
|
|
79007
|
+
const value = lookupField(name, positional, named, next);
|
|
79008
|
+
const spec = colon < 0 ? "" : render(field.slice(colon + 1));
|
|
79009
|
+
out += value === void 0 ? "" : formatValue(value, spec);
|
|
79010
|
+
i = j2 - 1;
|
|
79011
|
+
}
|
|
79012
|
+
return out;
|
|
79013
|
+
};
|
|
79014
|
+
return render(template);
|
|
79015
|
+
}
|
|
79016
|
+
|
|
79017
|
+
// packages/engine/src/lib/engines/jinja2.ts
|
|
78857
79018
|
var nunjucksBuiltinFilters = /* @__PURE__ */ new Set([
|
|
78858
79019
|
"abs",
|
|
78859
79020
|
"batch",
|
|
@@ -78908,7 +79069,12 @@ var builtinRoots2 = /* @__PURE__ */ new Set([
|
|
|
78908
79069
|
"joiner",
|
|
78909
79070
|
"lipsum",
|
|
78910
79071
|
"varargs",
|
|
78911
|
-
"kwargs"
|
|
79072
|
+
"kwargs",
|
|
79073
|
+
"namespace",
|
|
79074
|
+
// Jinja2's spelling of the literals, which the compat layer resolves at runtime
|
|
79075
|
+
"True",
|
|
79076
|
+
"False",
|
|
79077
|
+
"None"
|
|
78912
79078
|
]);
|
|
78913
79079
|
var stringMethods = {
|
|
78914
79080
|
upper: (s) => s.toUpperCase(),
|
|
@@ -78937,12 +79103,8 @@ var stringMethods = {
|
|
|
78937
79103
|
split: (s, sep, max) => sep === void 0 || sep === null ? s.trim().split(/\s+/) : s.split(String(sep), max === void 0 ? void 0 : Number(max) + 1),
|
|
78938
79104
|
join: (s, list2) => Array.isArray(list2) ? list2.join(s) : String(list2),
|
|
78939
79105
|
format: (s, ...args2) => {
|
|
78940
|
-
|
|
78941
|
-
|
|
78942
|
-
return s.replace(
|
|
78943
|
-
/\{(\w*)\}/g,
|
|
78944
|
-
(_2, key) => String(key ? named[key] ?? "" : args2[i++] ?? "")
|
|
78945
|
-
);
|
|
79106
|
+
const named = keywordArgs(args2);
|
|
79107
|
+
return pythonFormat(s, named ? args2.slice(0, -1) : args2, named ?? {});
|
|
78946
79108
|
},
|
|
78947
79109
|
zfill: (s, width) => s.padStart(Number(width), "0"),
|
|
78948
79110
|
count: (s, sub) => s.split(String(sub)).length - 1,
|
|
@@ -78957,6 +79119,92 @@ var stringMethods = {
|
|
|
78957
79119
|
return f2.repeat(left) + s + f2.repeat(total - left);
|
|
78958
79120
|
}
|
|
78959
79121
|
};
|
|
79122
|
+
function keywordArgs(args2) {
|
|
79123
|
+
const last = args2.at(-1);
|
|
79124
|
+
if (!last || typeof last !== "object" || !Object.prototype.hasOwnProperty.call(last, "__keywords")) return void 0;
|
|
79125
|
+
const { __keywords: _marker, ...named } = last;
|
|
79126
|
+
return named;
|
|
79127
|
+
}
|
|
79128
|
+
var JinjaNamespace = class {
|
|
79129
|
+
};
|
|
79130
|
+
function namespace(...args2) {
|
|
79131
|
+
const ns = new JinjaNamespace();
|
|
79132
|
+
const named = keywordArgs(args2);
|
|
79133
|
+
for (const arg of named ? [...args2.slice(0, -1), named] : args2)
|
|
79134
|
+
if (arg && typeof arg === "object") Object.assign(ns, arg);
|
|
79135
|
+
return ns;
|
|
79136
|
+
}
|
|
79137
|
+
function setNamespaceAttribute(target, key, value) {
|
|
79138
|
+
if (!(target instanceof JinjaNamespace)) throw new Error("Cannot assign attribute on non-namespace object");
|
|
79139
|
+
target[String(key)] = value;
|
|
79140
|
+
}
|
|
79141
|
+
var toList = (v2) => Array.isArray(v2) ? v2 : v2 === void 0 || v2 === null ? [] : typeof v2 === "string" ? [...v2] : [v2];
|
|
79142
|
+
var attributeOf = (item, path) => String(path ?? "").split(".").reduce((acc, key) => acc !== null && typeof acc === "object" ? acc[key] : void 0, item);
|
|
79143
|
+
var jinjaTests = {
|
|
79144
|
+
none: (v2) => v2 === null,
|
|
79145
|
+
true: (v2) => v2 === true,
|
|
79146
|
+
false: (v2) => v2 === false,
|
|
79147
|
+
in: (v2, container) => typeof container === "string" ? container.includes(String(v2)) : Array.isArray(container) ? container.includes(v2) : !!container && typeof container === "object" && String(v2) in container,
|
|
79148
|
+
"==": (v2, a) => v2 === a,
|
|
79149
|
+
"!=": (v2, a) => v2 !== a,
|
|
79150
|
+
">": (v2, a) => v2 > a,
|
|
79151
|
+
">=": (v2, a) => v2 >= a,
|
|
79152
|
+
"<": (v2, a) => v2 < a,
|
|
79153
|
+
"<=": (v2, a) => v2 <= a
|
|
79154
|
+
};
|
|
79155
|
+
function runTest(self2, name, value, arg) {
|
|
79156
|
+
const own = jinjaTests[name];
|
|
79157
|
+
if (own) return own(value, arg);
|
|
79158
|
+
return self2.env.getTest(name).call(self2, value, arg) === true;
|
|
79159
|
+
}
|
|
79160
|
+
function installJinjaFilters(env) {
|
|
79161
|
+
const lookup = env;
|
|
79162
|
+
const helperTruncate = lookup.getFilter("truncate");
|
|
79163
|
+
lookup.addFilter("truncate", function(value, ...args2) {
|
|
79164
|
+
const named = keywordArgs(args2);
|
|
79165
|
+
const p = named ? args2.slice(0, -1) : args2;
|
|
79166
|
+
if (!named && typeof p[1] !== "boolean" && p.length < 3) return helperTruncate.call(this, value, ...args2);
|
|
79167
|
+
const s = String(value ?? "");
|
|
79168
|
+
const length = Number(p[0] ?? named?.["length"] ?? 255);
|
|
79169
|
+
const killwords = Boolean(p[1] ?? named?.["killwords"] ?? false);
|
|
79170
|
+
const end = String(p[2] ?? named?.["end"] ?? "...");
|
|
79171
|
+
const leeway = Number(p[3] ?? named?.["leeway"] ?? 5);
|
|
79172
|
+
if (s.length <= length + leeway) return s;
|
|
79173
|
+
const cut = s.slice(0, Math.max(0, length - end.length));
|
|
79174
|
+
if (killwords) return cut + end;
|
|
79175
|
+
const space = cut.lastIndexOf(" ");
|
|
79176
|
+
return (space >= 0 ? cut.slice(0, space) : cut) + end;
|
|
79177
|
+
});
|
|
79178
|
+
const helperMap = lookup.getFilter("map");
|
|
79179
|
+
lookup.addFilter("map", function(value, ...args2) {
|
|
79180
|
+
const named = keywordArgs(args2);
|
|
79181
|
+
const p = named ? args2.slice(0, -1) : args2;
|
|
79182
|
+
if (named && "attribute" in named)
|
|
79183
|
+
return toList(value).map((item) => {
|
|
79184
|
+
const v2 = attributeOf(item, named["attribute"]);
|
|
79185
|
+
return v2 === void 0 && "default" in named ? named["default"] : v2;
|
|
79186
|
+
});
|
|
79187
|
+
const items = toList(value);
|
|
79188
|
+
if (typeof p[0] === "string" && !items.some((item) => item !== null && typeof item === "object")) {
|
|
79189
|
+
let filter;
|
|
79190
|
+
try {
|
|
79191
|
+
filter = lookup.getFilter(p[0]);
|
|
79192
|
+
} catch {
|
|
79193
|
+
filter = void 0;
|
|
79194
|
+
}
|
|
79195
|
+
if (filter) return items.map((item) => filter.call(this, item, ...p.slice(1)));
|
|
79196
|
+
}
|
|
79197
|
+
return helperMap.call(this, value, ...args2);
|
|
79198
|
+
});
|
|
79199
|
+
const byAttribute = (keep) => function(value, attribute, test, arg) {
|
|
79200
|
+
return toList(value).filter((item) => {
|
|
79201
|
+
const v2 = attributeOf(item, attribute);
|
|
79202
|
+
return (test === void 0 ? Boolean(v2) : runTest(this, String(test), v2, arg)) === keep;
|
|
79203
|
+
});
|
|
79204
|
+
};
|
|
79205
|
+
lookup.addFilter("selectattr", byAttribute(true));
|
|
79206
|
+
lookup.addFilter("rejectattr", byAttribute(false));
|
|
79207
|
+
}
|
|
78960
79208
|
function trimChars(s, chars, side) {
|
|
78961
79209
|
if (chars === void 0 || chars === null)
|
|
78962
79210
|
return side === "both" ? s.trim() : side === "left" ? s.trimStart() : s.trimEnd();
|
|
@@ -78977,6 +79225,20 @@ function installCompat() {
|
|
|
78977
79225
|
this.compile(node.target, frame);
|
|
78978
79226
|
this._emit(")");
|
|
78979
79227
|
};
|
|
79228
|
+
const compileSet = import_nunjucks.default.compiler.Compiler.prototype.compileSet;
|
|
79229
|
+
import_nunjucks.default.runtime["formfeedSetAttribute"] = setNamespaceAttribute;
|
|
79230
|
+
import_nunjucks.default.compiler.Compiler.prototype.compileSet = function(node, frame) {
|
|
79231
|
+
const [target, ...more] = node.targets;
|
|
79232
|
+
if (!target || more.length || target.typename !== "LookupVal") return compileSet.call(this, node, frame);
|
|
79233
|
+
this._emit("runtime.formfeedSetAttribute(");
|
|
79234
|
+
this._compileExpression(target["target"], frame);
|
|
79235
|
+
this._emit(", ");
|
|
79236
|
+
this._compileExpression(target["val"], frame);
|
|
79237
|
+
this._emit(", ");
|
|
79238
|
+
if (node.value) this._compileExpression(node.value, frame);
|
|
79239
|
+
else this.compile(node.body, frame);
|
|
79240
|
+
this._emitLine(");");
|
|
79241
|
+
};
|
|
78980
79242
|
const original = import_nunjucks.default.runtime.memberLookup;
|
|
78981
79243
|
import_nunjucks.default.runtime.memberLookup = (obj, val2, ...rest) => {
|
|
78982
79244
|
if (typeof obj === "string" && typeof val2 === "string" && Object.prototype.hasOwnProperty.call(stringMethods, val2)) {
|
|
@@ -79023,6 +79285,8 @@ function createEnvironment(ctx) {
|
|
|
79023
79285
|
env.addFilter(name, wrapped);
|
|
79024
79286
|
env.addGlobal(name, wrapped);
|
|
79025
79287
|
}
|
|
79288
|
+
env.addGlobal("namespace", namespace);
|
|
79289
|
+
installJinjaFilters(env);
|
|
79026
79290
|
return env;
|
|
79027
79291
|
}
|
|
79028
79292
|
var validationContext2 = {
|
|
@@ -79063,6 +79327,13 @@ function pathOf(node) {
|
|
|
79063
79327
|
function inScope(w, name) {
|
|
79064
79328
|
return w.scopes.some((s) => s.has(name));
|
|
79065
79329
|
}
|
|
79330
|
+
function sourceOf(w, name) {
|
|
79331
|
+
for (let i = w.scopes.length - 1; i >= 0; i--) {
|
|
79332
|
+
const scope = w.scopes[i];
|
|
79333
|
+
if (scope?.has(name)) return scope.get(name) ?? null;
|
|
79334
|
+
}
|
|
79335
|
+
return null;
|
|
79336
|
+
}
|
|
79066
79337
|
function walk2(node, w) {
|
|
79067
79338
|
if (!node || typeof node !== "object") return;
|
|
79068
79339
|
switch (node.typename) {
|
|
@@ -79071,10 +79342,12 @@ function walk2(node, w) {
|
|
|
79071
79342
|
const p = pathOf(node);
|
|
79072
79343
|
if (p) {
|
|
79073
79344
|
const root = p.path[0] ?? "";
|
|
79345
|
+
const bound = inScope(w, root);
|
|
79074
79346
|
w.variables.push({
|
|
79075
79347
|
path: p.path,
|
|
79076
79348
|
range: nodeRange(p.root, p.path.join(".").length),
|
|
79077
|
-
kind:
|
|
79349
|
+
kind: bound ? "loop-var" : "read",
|
|
79350
|
+
...bound ? { source: sourceOf(w, root) } : {}
|
|
79078
79351
|
});
|
|
79079
79352
|
}
|
|
79080
79353
|
if (node.typename === "LookupVal" && !p) {
|
|
@@ -79120,18 +79393,18 @@ function walk2(node, w) {
|
|
|
79120
79393
|
const source = pathOf(arr);
|
|
79121
79394
|
const nameNode = node["name"];
|
|
79122
79395
|
const names = nameNode.typename === "Array" ? nameNode.children ?? [] : [nameNode];
|
|
79123
|
-
const
|
|
79396
|
+
const root = source?.path[0] ?? "";
|
|
79397
|
+
const items = !source ? null : inScope(w, root) ? ((s) => s ? [...s, ...source.path.slice(1)] : null)(sourceOf(w, root)) : source.path;
|
|
79398
|
+
const scope = /* @__PURE__ */ new Map();
|
|
79124
79399
|
for (const n of names) {
|
|
79125
79400
|
const name = String(n.value);
|
|
79126
|
-
|
|
79127
|
-
|
|
79128
|
-
name,
|
|
79129
|
-
names.length === 1 && source && !inScope(w, source.path[0] ?? "") ? source.path : names.length === 1 && source ? resolveLoopSource(w, source.path) : null
|
|
79130
|
-
);
|
|
79401
|
+
const bound = names.length === 1 ? items : null;
|
|
79402
|
+
scope.set(name, bound);
|
|
79131
79403
|
w.variables.push({
|
|
79132
79404
|
path: [name],
|
|
79133
79405
|
range: nodeRange(n, name.length),
|
|
79134
|
-
kind: "loop-var"
|
|
79406
|
+
kind: "loop-var",
|
|
79407
|
+
source: bound
|
|
79135
79408
|
});
|
|
79136
79409
|
}
|
|
79137
79410
|
w.scopes.push(scope);
|
|
@@ -79149,8 +79422,7 @@ function walk2(node, w) {
|
|
|
79149
79422
|
range: nodeRange(p.root, p.path.join(".").length),
|
|
79150
79423
|
kind: "assigned"
|
|
79151
79424
|
});
|
|
79152
|
-
w.scopes[0]?.
|
|
79153
|
-
w.loopSources.set(p.path[0] ?? "", null);
|
|
79425
|
+
if (p.path.length === 1 || !inScope(w, p.path[0] ?? "")) w.scopes[0]?.set(p.path[0] ?? "", null);
|
|
79154
79426
|
}
|
|
79155
79427
|
}
|
|
79156
79428
|
walk2(node["value"], w);
|
|
@@ -79159,17 +79431,27 @@ function walk2(node, w) {
|
|
|
79159
79431
|
}
|
|
79160
79432
|
case "Macro": {
|
|
79161
79433
|
const args2 = node["args"];
|
|
79162
|
-
const scope = /* @__PURE__ */ new
|
|
79163
|
-
for (const child of args2.children ?? [])
|
|
79164
|
-
if (child.typename === "Symbol") scope.
|
|
79434
|
+
const scope = /* @__PURE__ */ new Map();
|
|
79435
|
+
for (const child of args2.children ?? []) {
|
|
79436
|
+
if (child.typename === "Symbol") scope.set(String(child.value), null);
|
|
79437
|
+
if (child.typename === "KeywordArgs")
|
|
79438
|
+
for (const pair of child.children ?? []) {
|
|
79439
|
+
const key = pair["key"];
|
|
79440
|
+
if (key) scope.set(String(key.value), null);
|
|
79441
|
+
walk2(pair["value"], w);
|
|
79442
|
+
}
|
|
79443
|
+
}
|
|
79165
79444
|
const nameNode = node["name"];
|
|
79166
|
-
w.scopes[0]?.
|
|
79167
|
-
w.loopSources.set(String(nameNode.value), null);
|
|
79445
|
+
w.scopes[0]?.set(String(nameNode.value), null);
|
|
79168
79446
|
w.scopes.push(scope);
|
|
79169
79447
|
walk2(node["body"], w);
|
|
79170
79448
|
w.scopes.pop();
|
|
79171
79449
|
return;
|
|
79172
79450
|
}
|
|
79451
|
+
case "Pair": {
|
|
79452
|
+
walk2(node["value"], w);
|
|
79453
|
+
return;
|
|
79454
|
+
}
|
|
79173
79455
|
case "Include":
|
|
79174
79456
|
case "Extends":
|
|
79175
79457
|
case "Import":
|
|
@@ -79182,15 +79464,17 @@ function walk2(node, w) {
|
|
|
79182
79464
|
});
|
|
79183
79465
|
else walk2(tpl, w);
|
|
79184
79466
|
if (node.typename === "Import")
|
|
79185
|
-
w.scopes[0]?.
|
|
79186
|
-
String(node["target"]?.value ?? "")
|
|
79467
|
+
w.scopes[0]?.set(
|
|
79468
|
+
String(node["target"]?.value ?? ""),
|
|
79469
|
+
null
|
|
79187
79470
|
);
|
|
79188
79471
|
if (node.typename === "FromImport")
|
|
79189
79472
|
for (const n of node["names"].children ?? [])
|
|
79190
|
-
w.scopes[0]?.
|
|
79473
|
+
w.scopes[0]?.set(
|
|
79191
79474
|
String(
|
|
79192
79475
|
n.typename === "Pair" ? n["value"].value : n.value
|
|
79193
|
-
)
|
|
79476
|
+
),
|
|
79477
|
+
null
|
|
79194
79478
|
);
|
|
79195
79479
|
return;
|
|
79196
79480
|
}
|
|
@@ -79208,12 +79492,6 @@ function walk2(node, w) {
|
|
|
79208
79492
|
walk2(value, w);
|
|
79209
79493
|
}
|
|
79210
79494
|
}
|
|
79211
|
-
function resolveLoopSource(w, path) {
|
|
79212
|
-
const root = path[0] ?? "";
|
|
79213
|
-
if (!w.loopSources.has(root)) return path;
|
|
79214
|
-
const source = w.loopSources.get(root);
|
|
79215
|
-
return source ? [...source, ...path.slice(1)] : null;
|
|
79216
|
-
}
|
|
79217
79495
|
function analyzeJinja2(source, opts = {}) {
|
|
79218
79496
|
const helpers = opts.helpers ?? defaultHelpers();
|
|
79219
79497
|
const { blocks, diagnostics } = scanBlocks(source, jinjaTags);
|
|
@@ -79221,8 +79499,7 @@ function analyzeJinja2(source, opts = {}) {
|
|
|
79221
79499
|
variables: [],
|
|
79222
79500
|
filters: [],
|
|
79223
79501
|
includes: [],
|
|
79224
|
-
|
|
79225
|
-
scopes: [/* @__PURE__ */ new Set()],
|
|
79502
|
+
scopes: [/* @__PURE__ */ new Map()],
|
|
79226
79503
|
helpers
|
|
79227
79504
|
};
|
|
79228
79505
|
try {
|
|
@@ -79251,6 +79528,13 @@ function analyzeJinja2(source, opts = {}) {
|
|
|
79251
79528
|
range: f2.range,
|
|
79252
79529
|
fix: { title: `Rename to ${preferred}`, replacement: preferred }
|
|
79253
79530
|
});
|
|
79531
|
+
} else if (unavailableHelper(f2.name)) {
|
|
79532
|
+
diagnostics.push({
|
|
79533
|
+
severity: "warning",
|
|
79534
|
+
code: "unavailable-helper",
|
|
79535
|
+
message: unavailableHelper(f2.name),
|
|
79536
|
+
range: f2.range
|
|
79537
|
+
});
|
|
79254
79538
|
} else if (!f2.known) {
|
|
79255
79539
|
diagnostics.push({
|
|
79256
79540
|
severity: "error",
|
|
@@ -79264,7 +79548,7 @@ function analyzeJinja2(source, opts = {}) {
|
|
|
79264
79548
|
const dataDiagnostics = missingPathDiagnostics(
|
|
79265
79549
|
w.variables,
|
|
79266
79550
|
opts.sampleData,
|
|
79267
|
-
|
|
79551
|
+
/* @__PURE__ */ new Map(),
|
|
79268
79552
|
builtin
|
|
79269
79553
|
);
|
|
79270
79554
|
return {
|
|
@@ -79397,6 +79681,10 @@ var liquidBuiltinFilters = /* @__PURE__ */ new Set([
|
|
|
79397
79681
|
"url_decode",
|
|
79398
79682
|
"url_encode",
|
|
79399
79683
|
"where",
|
|
79684
|
+
"where_exp",
|
|
79685
|
+
"find_exp",
|
|
79686
|
+
"reject_exp",
|
|
79687
|
+
"group_by_exp",
|
|
79400
79688
|
"raw",
|
|
79401
79689
|
"sum",
|
|
79402
79690
|
"group_by",
|
|
@@ -79651,6 +79939,13 @@ function analyzeLiquid(source, opts = {}) {
|
|
|
79651
79939
|
range: f2.range,
|
|
79652
79940
|
fix: { title: `Rename to ${preferred}`, replacement: preferred }
|
|
79653
79941
|
});
|
|
79942
|
+
} else if (unavailableHelper(f2.name)) {
|
|
79943
|
+
diagnostics.push({
|
|
79944
|
+
severity: "warning",
|
|
79945
|
+
code: "unavailable-helper",
|
|
79946
|
+
message: unavailableHelper(f2.name),
|
|
79947
|
+
range: f2.range
|
|
79948
|
+
});
|
|
79654
79949
|
} else if (!f2.known) {
|
|
79655
79950
|
diagnostics.push({
|
|
79656
79951
|
severity: "error",
|
|
@@ -80069,6 +80364,11 @@ ${loop(e, "line", "invoice.lines", ` <tr><td>${val(e, "line.description")}</t
|
|
|
80069
80364
|
}
|
|
80070
80365
|
];
|
|
80071
80366
|
|
|
80367
|
+
// packages/api-types/src/lib/assets.ts
|
|
80368
|
+
var SEGMENT = "[A-Za-z0-9][A-Za-z0-9._-]*";
|
|
80369
|
+
var ASSET_NAME_PATTERN = new RegExp(`^${SEGMENT}(?:/${SEGMENT})*$`);
|
|
80370
|
+
var ASSET_MAX_BYTES = 10 * 1024 * 1024;
|
|
80371
|
+
|
|
80072
80372
|
// packages/sdk-ts/src/lib/client.ts
|
|
80073
80373
|
var FormfeedError = class extends Error {
|
|
80074
80374
|
constructor(code, message2, status, problem = null, requestId = null) {
|
|
@@ -80096,6 +80396,8 @@ function randomKey() {
|
|
|
80096
80396
|
if (c?.randomUUID) return c.randomUUID();
|
|
80097
80397
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
80098
80398
|
}
|
|
80399
|
+
var withKey = (options) => ({ ...options, idempotencyKey: options.idempotencyKey ?? randomKey() });
|
|
80400
|
+
var idOf = (source) => typeof source === "string" ? source : source.id;
|
|
80099
80401
|
var Formfeed = class {
|
|
80100
80402
|
baseUrl;
|
|
80101
80403
|
apiKey;
|
|
@@ -80164,6 +80466,54 @@ var Formfeed = class {
|
|
|
80164
80466
|
idempotencyKey: options.idempotencyKey ?? randomKey()
|
|
80165
80467
|
})
|
|
80166
80468
|
};
|
|
80469
|
+
/**
|
|
80470
|
+
* PDF tools on the outputs of earlier renders (a `Render` or its id) and on PDFs of the file library
|
|
80471
|
+
* (a `LibraryFile`, its id or its name). merge, protect and watermark return a new render and cost
|
|
80472
|
+
* 0.5 units each on live keys; info is free.
|
|
80473
|
+
*/
|
|
80474
|
+
pdf = {
|
|
80475
|
+
merge: (sources, output = {}, options = {}) => this.request("POST", "/pdf/merge", { ...output, sources: sources.map(idOf) }, withKey(options)),
|
|
80476
|
+
protect: (source, protect, options = {}) => this.request("POST", "/pdf/protect", { ...protect, source: idOf(source) }, withKey(options)),
|
|
80477
|
+
watermark: (source, watermark, options = {}) => this.request("POST", "/pdf/watermark", { ...watermark, source: idOf(source) }, withKey(options)),
|
|
80478
|
+
info: (source, options = {}) => this.request("POST", "/pdf/info", { source: idOf(source) }, options)
|
|
80479
|
+
};
|
|
80480
|
+
/**
|
|
80481
|
+
* The workspace file library (`/files`): images and PDFs a template references by name with
|
|
80482
|
+
* `asset('logo.png')`, and the sources of image watermarks and merges. Needs `file:read`,
|
|
80483
|
+
* `file:write` or `file:delete`. Files are served without a signature, so keep confidential
|
|
80484
|
+
* documents out of it.
|
|
80485
|
+
*/
|
|
80486
|
+
files = {
|
|
80487
|
+
/** Uploads a file; the same name replaces the existing file in place and keeps its URL. */
|
|
80488
|
+
upload: (file, options = {}) => {
|
|
80489
|
+
const blob = file.data instanceof Blob ? file.data : new Blob([file.data], file.contentType ? { type: file.contentType } : {});
|
|
80490
|
+
const form = new FormData();
|
|
80491
|
+
form.set("file", blob, file.name);
|
|
80492
|
+
form.set("name", file.name);
|
|
80493
|
+
return this.request("POST", "/files", form, options);
|
|
80494
|
+
},
|
|
80495
|
+
/** Page of files, newest first. */
|
|
80496
|
+
list: (query = {}, options = {}) => {
|
|
80497
|
+
const params = new URLSearchParams();
|
|
80498
|
+
for (const [k2, v2] of Object.entries(query)) if (v2 !== void 0 && v2 !== null && v2 !== "") params.set(k2, String(v2));
|
|
80499
|
+
const qs = params.toString();
|
|
80500
|
+
return this.request("GET", `/files${qs ? `?${qs}` : ""}`, void 0, options);
|
|
80501
|
+
},
|
|
80502
|
+
/** Every file matching the query, following the cursor. */
|
|
80503
|
+
all: async (query = {}, options = {}) => {
|
|
80504
|
+
const out = [];
|
|
80505
|
+
let cursor = null;
|
|
80506
|
+
do {
|
|
80507
|
+
const page = await this.files.list({ ...query, cursor }, options);
|
|
80508
|
+
out.push(...page.data);
|
|
80509
|
+
cursor = page.next_cursor;
|
|
80510
|
+
} while (cursor);
|
|
80511
|
+
return out;
|
|
80512
|
+
},
|
|
80513
|
+
get: (id, options = {}) => this.request("GET", `/files/${encodeURIComponent(id)}`, void 0, options),
|
|
80514
|
+
/** Removes the file and its bytes; templates that name it render a missing image afterwards. */
|
|
80515
|
+
delete: (file, options = {}) => this.request("DELETE", `/files/${encodeURIComponent(idOf(file))}`, void 0, options)
|
|
80516
|
+
};
|
|
80167
80517
|
jobs = {
|
|
80168
80518
|
get: (id, options = {}) => this.request("GET", `/jobs/${encodeURIComponent(id)}`, void 0, options),
|
|
80169
80519
|
waitFor: async (id, options = {}) => {
|
|
@@ -80214,7 +80564,13 @@ var Formfeed = class {
|
|
|
80214
80564
|
create: (idOrSlug, input, options = {}) => this.request("POST", `/templates/${encodeURIComponent(idOrSlug)}/versions`, input, options),
|
|
80215
80565
|
publish: (idOrSlug, number, options = {}) => this.request("POST", `/templates/${encodeURIComponent(idOrSlug)}/versions/${number}/publish`, void 0, options)
|
|
80216
80566
|
},
|
|
80217
|
-
schema: (idOrSlug, options = {}) => this.request("GET", `/templates/${encodeURIComponent(idOrSlug)}/schema`, void 0, options)
|
|
80567
|
+
schema: (idOrSlug, options = {}) => this.request("GET", `/templates/${encodeURIComponent(idOrSlug)}/schema`, void 0, options),
|
|
80568
|
+
/**
|
|
80569
|
+
* Checks a version with data without rendering: syntax, header and footer, missing partials,
|
|
80570
|
+
* runtime errors and the data against the stored schema. Free. Without `data`, the version's
|
|
80571
|
+
* sample data is checked.
|
|
80572
|
+
*/
|
|
80573
|
+
validate: (idOrSlug, input = {}, options = {}) => this.request("POST", `/templates/${encodeURIComponent(idOrSlug)}/validate`, input, options)
|
|
80218
80574
|
};
|
|
80219
80575
|
account = {
|
|
80220
80576
|
get: (options = {}) => this.request("GET", "/account", void 0, options),
|
|
@@ -80227,9 +80583,10 @@ var Formfeed = class {
|
|
|
80227
80583
|
const headers = {
|
|
80228
80584
|
authorization: `Bearer ${this.apiKey}`,
|
|
80229
80585
|
accept: "application/json",
|
|
80230
|
-
"user-agent": "formfeed-sdk-ts/0.
|
|
80586
|
+
"user-agent": "formfeed-sdk-ts/0.2"
|
|
80231
80587
|
};
|
|
80232
|
-
|
|
80588
|
+
const isForm = typeof FormData !== "undefined" && body instanceof FormData;
|
|
80589
|
+
if (body !== void 0 && !isForm) headers["content-type"] = "application/json";
|
|
80233
80590
|
if (options.idempotencyKey) headers["idempotency-key"] = options.idempotencyKey;
|
|
80234
80591
|
let attempt = 0;
|
|
80235
80592
|
for (; ; ) {
|
|
@@ -80241,7 +80598,7 @@ var Formfeed = class {
|
|
|
80241
80598
|
res = await this.fetchImpl(url, {
|
|
80242
80599
|
method,
|
|
80243
80600
|
headers,
|
|
80244
|
-
body: body === void 0 ? void 0 : JSON.stringify(body),
|
|
80601
|
+
body: body === void 0 ? void 0 : isForm ? body : JSON.stringify(body),
|
|
80245
80602
|
signal: controller.signal
|
|
80246
80603
|
});
|
|
80247
80604
|
} catch (e) {
|
|
@@ -80287,7 +80644,7 @@ var encoder2 = new TextEncoder();
|
|
|
80287
80644
|
|
|
80288
80645
|
// packages/mcp/src/lib/server.ts
|
|
80289
80646
|
import { z as z2 } from "zod";
|
|
80290
|
-
var SERVER_INFO = { name: "formfeed", version: "0.
|
|
80647
|
+
var SERVER_INFO = { name: "formfeed", version: "0.2.0" };
|
|
80291
80648
|
var engineSchema = z2.enum(["jinja2", "liquid", "handlebars"]);
|
|
80292
80649
|
var outputSchema = z2.enum(["pdf", "png", "jpg"]);
|
|
80293
80650
|
var templateSummary = (t) => ({
|
package/package.json
CHANGED