@ceupay/template-cli 0.1.0-alpha.2 → 0.1.0-alpha.3
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/CHANGELOG.md +8 -0
- package/README.md +28 -0
- package/dist/main.cjs +672 -124
- package/dist/third-party-notices.txt +60 -0
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -49,7 +49,7 @@ var require_liquid_node = __commonJS({
|
|
|
49
49
|
"use strict";
|
|
50
50
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
51
51
|
var stream = require("stream");
|
|
52
|
-
var
|
|
52
|
+
var path4 = require("path");
|
|
53
53
|
var fs$1 = require("fs");
|
|
54
54
|
var crypto = require("crypto");
|
|
55
55
|
var Token = class {
|
|
@@ -1511,9 +1511,9 @@ var require_liquid_node = __commonJS({
|
|
|
1511
1511
|
return fs$1.readFileSync(filepath, "utf8");
|
|
1512
1512
|
}
|
|
1513
1513
|
function resolve(root, file, ext) {
|
|
1514
|
-
if (!
|
|
1514
|
+
if (!path4.extname(file))
|
|
1515
1515
|
file += ext;
|
|
1516
|
-
return
|
|
1516
|
+
return path4.resolve(root, file);
|
|
1517
1517
|
}
|
|
1518
1518
|
function fallback(file) {
|
|
1519
1519
|
try {
|
|
@@ -1522,14 +1522,14 @@ var require_liquid_node = __commonJS({
|
|
|
1522
1522
|
}
|
|
1523
1523
|
}
|
|
1524
1524
|
function dirname(filepath) {
|
|
1525
|
-
return
|
|
1525
|
+
return path4.dirname(filepath);
|
|
1526
1526
|
}
|
|
1527
1527
|
var realpathAsync = promisify(fs$1.realpath);
|
|
1528
1528
|
async function contains(root, file) {
|
|
1529
1529
|
try {
|
|
1530
1530
|
const realRoot = await realpathAsync(root);
|
|
1531
1531
|
const realFile = await realpathAsync(file);
|
|
1532
|
-
const prefix = realRoot.endsWith(
|
|
1532
|
+
const prefix = realRoot.endsWith(path4.sep) ? realRoot : realRoot + path4.sep;
|
|
1533
1533
|
return realFile.startsWith(prefix);
|
|
1534
1534
|
} catch {
|
|
1535
1535
|
return false;
|
|
@@ -1539,13 +1539,13 @@ var require_liquid_node = __commonJS({
|
|
|
1539
1539
|
try {
|
|
1540
1540
|
const realRoot = fs$1.realpathSync(root);
|
|
1541
1541
|
const realFile = fs$1.realpathSync(file);
|
|
1542
|
-
const prefix = realRoot.endsWith(
|
|
1542
|
+
const prefix = realRoot.endsWith(path4.sep) ? realRoot : realRoot + path4.sep;
|
|
1543
1543
|
return realFile.startsWith(prefix);
|
|
1544
1544
|
} catch {
|
|
1545
1545
|
return false;
|
|
1546
1546
|
}
|
|
1547
1547
|
}
|
|
1548
|
-
var
|
|
1548
|
+
var fs4 = /* @__PURE__ */ Object.freeze({
|
|
1549
1549
|
__proto__: null,
|
|
1550
1550
|
exists,
|
|
1551
1551
|
readFile,
|
|
@@ -1556,7 +1556,7 @@ var require_liquid_node = __commonJS({
|
|
|
1556
1556
|
dirname,
|
|
1557
1557
|
contains,
|
|
1558
1558
|
containsSync,
|
|
1559
|
-
sep:
|
|
1559
|
+
sep: path4.sep
|
|
1560
1560
|
});
|
|
1561
1561
|
function chargeJsonReplacerValue(memoryLimit, val) {
|
|
1562
1562
|
if (typeof val === "string") {
|
|
@@ -1632,13 +1632,13 @@ var require_liquid_node = __commonJS({
|
|
|
1632
1632
|
""": '"',
|
|
1633
1633
|
"'": "'"
|
|
1634
1634
|
};
|
|
1635
|
-
function
|
|
1635
|
+
function escape4(str3) {
|
|
1636
1636
|
str3 = stringify(str3);
|
|
1637
1637
|
this.context.memoryLimit.use(str3.length);
|
|
1638
1638
|
return str3.replace(/&|<|>|"|'/g, (m) => escapeMap[m]);
|
|
1639
1639
|
}
|
|
1640
1640
|
function xml_escape(str3) {
|
|
1641
|
-
return
|
|
1641
|
+
return escape4.call(this, str3);
|
|
1642
1642
|
}
|
|
1643
1643
|
function unescape2(str3) {
|
|
1644
1644
|
str3 = stringify(str3);
|
|
@@ -1646,7 +1646,7 @@ var require_liquid_node = __commonJS({
|
|
|
1646
1646
|
return str3.replace(/&(amp|lt|gt|#34|#39);/g, (m) => unescapeMap[m]);
|
|
1647
1647
|
}
|
|
1648
1648
|
function escape_once(str3) {
|
|
1649
|
-
return
|
|
1649
|
+
return escape4.call(this, unescape2.call(this, str3));
|
|
1650
1650
|
}
|
|
1651
1651
|
function newline_to_br(v) {
|
|
1652
1652
|
const str3 = stringify(v);
|
|
@@ -1681,7 +1681,7 @@ var require_liquid_node = __commonJS({
|
|
|
1681
1681
|
}
|
|
1682
1682
|
var htmlFilters = /* @__PURE__ */ Object.freeze({
|
|
1683
1683
|
__proto__: null,
|
|
1684
|
-
escape:
|
|
1684
|
+
escape: escape4,
|
|
1685
1685
|
xml_escape,
|
|
1686
1686
|
escape_once,
|
|
1687
1687
|
newline_to_br,
|
|
@@ -1738,7 +1738,7 @@ var require_liquid_node = __commonJS({
|
|
|
1738
1738
|
keyValueSeparator: ":",
|
|
1739
1739
|
cache: void 0,
|
|
1740
1740
|
extname: "",
|
|
1741
|
-
fs:
|
|
1741
|
+
fs: fs4,
|
|
1742
1742
|
dynamicPartials: true,
|
|
1743
1743
|
jsTruthy: false,
|
|
1744
1744
|
dateFormat: "%A, %B %-e, %Y at %-l:%M %P %z",
|
|
@@ -1803,7 +1803,7 @@ var require_liquid_node = __commonJS({
|
|
|
1803
1803
|
}
|
|
1804
1804
|
function getOutputEscapeFunction(nameOrFunction) {
|
|
1805
1805
|
if (nameOrFunction === "escape")
|
|
1806
|
-
return
|
|
1806
|
+
return escape4;
|
|
1807
1807
|
if (nameOrFunction === "json")
|
|
1808
1808
|
return misc.json;
|
|
1809
1809
|
assert(isFunction(nameOrFunction), "`outputEscape` need to be of type string or function");
|
|
@@ -2100,10 +2100,10 @@ var require_liquid_node = __commonJS({
|
|
|
2100
2100
|
readHashes(jekyllStyle) {
|
|
2101
2101
|
const hashes = [];
|
|
2102
2102
|
while (true) {
|
|
2103
|
-
const
|
|
2104
|
-
if (!
|
|
2103
|
+
const hash2 = this.readHash(jekyllStyle);
|
|
2104
|
+
if (!hash2)
|
|
2105
2105
|
return hashes;
|
|
2106
|
-
hashes.push(
|
|
2106
|
+
hashes.push(hash2);
|
|
2107
2107
|
}
|
|
2108
2108
|
}
|
|
2109
2109
|
readHash(jekyllStyle) {
|
|
@@ -2360,16 +2360,16 @@ var require_liquid_node = __commonJS({
|
|
|
2360
2360
|
constructor(input, jekyllStyle) {
|
|
2361
2361
|
this.hash = {};
|
|
2362
2362
|
const tokenizer = input instanceof Tokenizer2 ? input : new Tokenizer2(input, {});
|
|
2363
|
-
for (const
|
|
2364
|
-
this.hash[
|
|
2363
|
+
for (const hash2 of tokenizer.readHashes(jekyllStyle)) {
|
|
2364
|
+
this.hash[hash2.name.content] = hash2.value;
|
|
2365
2365
|
}
|
|
2366
2366
|
}
|
|
2367
2367
|
*render(ctx) {
|
|
2368
|
-
const
|
|
2368
|
+
const hash2 = {};
|
|
2369
2369
|
for (const key of Object.keys(this.hash)) {
|
|
2370
|
-
|
|
2370
|
+
hash2[key] = this.hash[key] === void 0 ? true : yield evalToken(this.hash[key], ctx);
|
|
2371
2371
|
}
|
|
2372
|
-
return
|
|
2372
|
+
return hash2;
|
|
2373
2373
|
}
|
|
2374
2374
|
};
|
|
2375
2375
|
function createTagClass(options) {
|
|
@@ -2381,8 +2381,8 @@ var require_liquid_node = __commonJS({
|
|
|
2381
2381
|
}
|
|
2382
2382
|
}
|
|
2383
2383
|
*render(ctx, emitter) {
|
|
2384
|
-
const
|
|
2385
|
-
return yield options.render.call(this, ctx, emitter,
|
|
2384
|
+
const hash2 = yield new Hash(this.token.args, ctx.opts.keyValueSeparator).render(ctx);
|
|
2385
|
+
return yield options.render.call(this, ctx, emitter, hash2);
|
|
2386
2386
|
}
|
|
2387
2387
|
};
|
|
2388
2388
|
}
|
|
@@ -2757,9 +2757,9 @@ var require_liquid_node = __commonJS({
|
|
|
2757
2757
|
} else {
|
|
2758
2758
|
this.shouldLoadRelative = (_referencedFile) => false;
|
|
2759
2759
|
}
|
|
2760
|
-
const
|
|
2761
|
-
this.contains = toLiquidAsync(
|
|
2762
|
-
this.exists = toLiquidAsync(
|
|
2760
|
+
const fs5 = options.fs;
|
|
2761
|
+
this.contains = toLiquidAsync(fs5.contains?.bind(fs5) || (async () => true), fs5.containsSync?.bind(fs5) || (() => true));
|
|
2762
|
+
this.exists = toLiquidAsync(fs5.exists?.bind(fs5) || (async () => false), fs5.existsSync?.bind(fs5));
|
|
2763
2763
|
}
|
|
2764
2764
|
*lookup(file, type, sync, currentFile) {
|
|
2765
2765
|
const dirs = this.options[type];
|
|
@@ -2779,25 +2779,25 @@ var require_liquid_node = __commonJS({
|
|
|
2779
2779
|
throw this.lookupError(file, dirs);
|
|
2780
2780
|
}
|
|
2781
2781
|
*candidates(file, dirs, currentFile) {
|
|
2782
|
-
const { fs:
|
|
2782
|
+
const { fs: fs5, extname } = this.options;
|
|
2783
2783
|
if (this.shouldLoadRelative(file) && currentFile) {
|
|
2784
|
-
const referenced =
|
|
2784
|
+
const referenced = fs5.resolve(this.dirname(currentFile), file, extname);
|
|
2785
2785
|
yield referenced;
|
|
2786
2786
|
}
|
|
2787
2787
|
for (const dir of dirs) {
|
|
2788
|
-
const referenced =
|
|
2788
|
+
const referenced = fs5.resolve(dir, file, extname);
|
|
2789
2789
|
yield referenced;
|
|
2790
2790
|
}
|
|
2791
|
-
if (
|
|
2792
|
-
const filepath =
|
|
2791
|
+
if (fs5.fallback !== void 0) {
|
|
2792
|
+
const filepath = fs5.fallback(file);
|
|
2793
2793
|
if (filepath !== void 0)
|
|
2794
2794
|
yield filepath;
|
|
2795
2795
|
}
|
|
2796
2796
|
}
|
|
2797
|
-
dirname(
|
|
2798
|
-
const
|
|
2799
|
-
assert(
|
|
2800
|
-
return
|
|
2797
|
+
dirname(path5) {
|
|
2798
|
+
const fs5 = this.options.fs;
|
|
2799
|
+
assert(fs5.dirname, "`fs.dirname` is required for relative reference");
|
|
2800
|
+
return fs5.dirname(path5);
|
|
2801
2801
|
}
|
|
2802
2802
|
lookupError(file, roots) {
|
|
2803
2803
|
const err = new Error("ENOENT");
|
|
@@ -3866,17 +3866,17 @@ var require_liquid_node = __commonJS({
|
|
|
3866
3866
|
}
|
|
3867
3867
|
const continueKey = "continue-" + this.variable + "-" + this.collection.getText();
|
|
3868
3868
|
ctx.push(createScope({ continue: ctx.getRegister(continueKey, {}) }));
|
|
3869
|
-
const
|
|
3869
|
+
const hash2 = yield this.hash.render(ctx);
|
|
3870
3870
|
ctx.pop();
|
|
3871
|
-
const modifiers = this.liquid.options.orderedFilterParameters ? Object.keys(
|
|
3871
|
+
const modifiers = this.liquid.options.orderedFilterParameters ? Object.keys(hash2).filter((x) => MODIFIERS.includes(x)) : MODIFIERS.filter((x) => hash2[x] !== void 0);
|
|
3872
3872
|
collection = modifiers.reduce((collection2, modifier) => {
|
|
3873
3873
|
if (modifier === "offset")
|
|
3874
|
-
return offset(collection2,
|
|
3874
|
+
return offset(collection2, hash2["offset"]);
|
|
3875
3875
|
if (modifier === "limit")
|
|
3876
|
-
return limit(collection2,
|
|
3876
|
+
return limit(collection2, hash2["limit"]);
|
|
3877
3877
|
return reversed(collection2);
|
|
3878
3878
|
}, collection);
|
|
3879
|
-
ctx.setRegister(continueKey, (
|
|
3879
|
+
ctx.setRegister(continueKey, (hash2["offset"] || 0) + collection.length);
|
|
3880
3880
|
const scope = createScope({ forloop: new ForloopDrop(collection.length, this.collection.getText(), this.variable) });
|
|
3881
3881
|
ctx.push(scope);
|
|
3882
3882
|
for (const item of collection) {
|
|
@@ -4076,12 +4076,12 @@ var require_liquid_node = __commonJS({
|
|
|
4076
4076
|
this.hash = new Hash(tokenizer, liquid.options.keyValueSeparator);
|
|
4077
4077
|
}
|
|
4078
4078
|
*render(ctx, emitter) {
|
|
4079
|
-
const { liquid, hash } = this;
|
|
4079
|
+
const { liquid, hash: hash2 } = this;
|
|
4080
4080
|
const filepath = yield renderFilePath(this.file, ctx, liquid);
|
|
4081
4081
|
assert(filepath, () => `illegal file path "${filepath}"`);
|
|
4082
4082
|
const childCtx = ctx.spawn();
|
|
4083
4083
|
const scope = childCtx.bottom();
|
|
4084
|
-
__assign(scope, yield
|
|
4084
|
+
__assign(scope, yield hash2.render(ctx));
|
|
4085
4085
|
if (this.with) {
|
|
4086
4086
|
const { value, alias } = this.with;
|
|
4087
4087
|
scope[alias || filepath] = yield evalToken(value, ctx);
|
|
@@ -4196,14 +4196,14 @@ var require_liquid_node = __commonJS({
|
|
|
4196
4196
|
this.hash = new Hash(tokenizer, liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
|
|
4197
4197
|
}
|
|
4198
4198
|
*render(ctx, emitter) {
|
|
4199
|
-
const { liquid, hash, withVar } = this;
|
|
4199
|
+
const { liquid, hash: hash2, withVar } = this;
|
|
4200
4200
|
const { renderer } = liquid;
|
|
4201
4201
|
const filepath = yield renderFilePath(this.file, ctx, liquid);
|
|
4202
4202
|
assert(filepath, () => `illegal file path "${filepath}"`);
|
|
4203
4203
|
const saved = ctx.saveRegister("blocks", "blockMode");
|
|
4204
4204
|
ctx.setRegister("blocks", {});
|
|
4205
4205
|
ctx.setRegister("blockMode", BlockMode.OUTPUT);
|
|
4206
|
-
const scope = createScope(yield
|
|
4206
|
+
const scope = createScope(yield hash2.render(ctx));
|
|
4207
4207
|
if (withVar)
|
|
4208
4208
|
scope[filepath] = yield evalToken(withVar, ctx);
|
|
4209
4209
|
const templates = yield liquid._parsePartialFile(filepath, ctx.sync, this.currentFile);
|
|
@@ -5038,7 +5038,7 @@ var require_tokenize = __commonJS({
|
|
|
5038
5038
|
module2.exports = function tokenizer(input, options = {}) {
|
|
5039
5039
|
let css = input.css.valueOf();
|
|
5040
5040
|
let ignore = options.ignoreErrors;
|
|
5041
|
-
let code, content,
|
|
5041
|
+
let code, content, escape4, next, quote;
|
|
5042
5042
|
let currentToken, escaped, escapePos, n, prev;
|
|
5043
5043
|
let length = css.length;
|
|
5044
5044
|
let pos = 0;
|
|
@@ -5163,13 +5163,13 @@ var require_tokenize = __commonJS({
|
|
|
5163
5163
|
}
|
|
5164
5164
|
case BACKSLASH: {
|
|
5165
5165
|
next = pos;
|
|
5166
|
-
|
|
5166
|
+
escape4 = true;
|
|
5167
5167
|
while (css.charCodeAt(next + 1) === BACKSLASH) {
|
|
5168
5168
|
next += 1;
|
|
5169
|
-
|
|
5169
|
+
escape4 = !escape4;
|
|
5170
5170
|
}
|
|
5171
5171
|
code = css.charCodeAt(next + 1);
|
|
5172
|
-
if (
|
|
5172
|
+
if (escape4 && code !== SLASH && code !== SPACE && code !== NEWLINE && code !== TAB && code !== CR && code !== FEED) {
|
|
5173
5173
|
next += 1;
|
|
5174
5174
|
if (RE_HEX_ESCAPE.test(css.charAt(next))) {
|
|
5175
5175
|
while (RE_HEX_ESCAPE.test(css.charAt(next + 1))) {
|
|
@@ -6956,27 +6956,27 @@ var require_util = __commonJS({
|
|
|
6956
6956
|
};
|
|
6957
6957
|
}
|
|
6958
6958
|
var normalize = lruMemoize(function normalize2(aPath) {
|
|
6959
|
-
var
|
|
6959
|
+
var path4 = aPath;
|
|
6960
6960
|
var url = urlParse(aPath);
|
|
6961
6961
|
if (url) {
|
|
6962
6962
|
if (!url.path) {
|
|
6963
6963
|
return aPath;
|
|
6964
6964
|
}
|
|
6965
|
-
|
|
6965
|
+
path4 = url.path;
|
|
6966
6966
|
}
|
|
6967
|
-
var isAbsolute = exports2.isAbsolute(
|
|
6967
|
+
var isAbsolute = exports2.isAbsolute(path4);
|
|
6968
6968
|
var parts = [];
|
|
6969
6969
|
var start = 0;
|
|
6970
6970
|
var i = 0;
|
|
6971
6971
|
while (true) {
|
|
6972
6972
|
start = i;
|
|
6973
|
-
i =
|
|
6973
|
+
i = path4.indexOf("/", start);
|
|
6974
6974
|
if (i === -1) {
|
|
6975
|
-
parts.push(
|
|
6975
|
+
parts.push(path4.slice(start));
|
|
6976
6976
|
break;
|
|
6977
6977
|
} else {
|
|
6978
|
-
parts.push(
|
|
6979
|
-
while (i <
|
|
6978
|
+
parts.push(path4.slice(start, i));
|
|
6979
|
+
while (i < path4.length && path4[i] === "/") {
|
|
6980
6980
|
i++;
|
|
6981
6981
|
}
|
|
6982
6982
|
}
|
|
@@ -6997,15 +6997,15 @@ var require_util = __commonJS({
|
|
|
6997
6997
|
}
|
|
6998
6998
|
}
|
|
6999
6999
|
}
|
|
7000
|
-
|
|
7001
|
-
if (
|
|
7002
|
-
|
|
7000
|
+
path4 = parts.join("/");
|
|
7001
|
+
if (path4 === "") {
|
|
7002
|
+
path4 = isAbsolute ? "/" : ".";
|
|
7003
7003
|
}
|
|
7004
7004
|
if (url) {
|
|
7005
|
-
url.path =
|
|
7005
|
+
url.path = path4;
|
|
7006
7006
|
return urlGenerate(url);
|
|
7007
7007
|
}
|
|
7008
|
-
return
|
|
7008
|
+
return path4;
|
|
7009
7009
|
});
|
|
7010
7010
|
exports2.normalize = normalize;
|
|
7011
7011
|
function join(aRoot, aPath) {
|
|
@@ -8730,11 +8730,11 @@ var require_previous_map = __commonJS({
|
|
|
8730
8730
|
var { existsSync, readFileSync, realpathSync } = require("fs");
|
|
8731
8731
|
var { dirname, isAbsolute, join, relative, sep } = require("path");
|
|
8732
8732
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
8733
|
-
function realPath(
|
|
8733
|
+
function realPath(path4) {
|
|
8734
8734
|
try {
|
|
8735
|
-
return realpathSync(
|
|
8735
|
+
return realpathSync(path4);
|
|
8736
8736
|
} catch {
|
|
8737
|
-
return
|
|
8737
|
+
return path4;
|
|
8738
8738
|
}
|
|
8739
8739
|
}
|
|
8740
8740
|
function fromBase64(str3) {
|
|
@@ -8797,19 +8797,19 @@ var require_previous_map = __commonJS({
|
|
|
8797
8797
|
this.annotation = this.getAnnotationURL(css.substring(start, end));
|
|
8798
8798
|
}
|
|
8799
8799
|
}
|
|
8800
|
-
loadFile(
|
|
8800
|
+
loadFile(path4, cssFile, trusted) {
|
|
8801
8801
|
if (!trusted && !this.unsafeMap) {
|
|
8802
|
-
if (!/\.map$/i.test(
|
|
8802
|
+
if (!/\.map$/i.test(path4)) return void 0;
|
|
8803
8803
|
if (!cssFile) return void 0;
|
|
8804
|
-
let rel = relative(realPath(dirname(cssFile)), realPath(
|
|
8804
|
+
let rel = relative(realPath(dirname(cssFile)), realPath(path4));
|
|
8805
8805
|
if (rel === ".." || rel.startsWith(".." + sep) || isAbsolute(rel)) {
|
|
8806
8806
|
return void 0;
|
|
8807
8807
|
}
|
|
8808
8808
|
}
|
|
8809
|
-
this.root = dirname(
|
|
8810
|
-
if (existsSync(
|
|
8811
|
-
this.mapFile =
|
|
8812
|
-
return readFileSync(
|
|
8809
|
+
this.root = dirname(path4);
|
|
8810
|
+
if (existsSync(path4)) {
|
|
8811
|
+
this.mapFile = path4;
|
|
8812
|
+
return readFileSync(path4, "utf-8").toString().trim();
|
|
8813
8813
|
}
|
|
8814
8814
|
}
|
|
8815
8815
|
loadMap(file, prev) {
|
|
@@ -9184,7 +9184,7 @@ var require_list = __commonJS({
|
|
|
9184
9184
|
let func = 0;
|
|
9185
9185
|
let inQuote = false;
|
|
9186
9186
|
let prevQuote = "";
|
|
9187
|
-
let
|
|
9187
|
+
let escape4 = false;
|
|
9188
9188
|
let inComment = false;
|
|
9189
9189
|
for (let i = 0; i < string.length; i++) {
|
|
9190
9190
|
let letter = string[i];
|
|
@@ -9197,10 +9197,10 @@ var require_list = __commonJS({
|
|
|
9197
9197
|
}
|
|
9198
9198
|
continue;
|
|
9199
9199
|
}
|
|
9200
|
-
if (
|
|
9201
|
-
|
|
9200
|
+
if (escape4) {
|
|
9201
|
+
escape4 = false;
|
|
9202
9202
|
} else if (letter === "\\") {
|
|
9203
|
-
|
|
9203
|
+
escape4 = true;
|
|
9204
9204
|
} else if (inQuote) {
|
|
9205
9205
|
if (letter === prevQuote) {
|
|
9206
9206
|
inQuote = false;
|
|
@@ -9605,9 +9605,9 @@ var require_map_generator = __commonJS({
|
|
|
9605
9605
|
if (typeof this.mapOpts.annotation === "string") {
|
|
9606
9606
|
from = dirname(resolve(from, this.mapOpts.annotation));
|
|
9607
9607
|
}
|
|
9608
|
-
let
|
|
9609
|
-
this.memoizedPaths.set(file,
|
|
9610
|
-
return
|
|
9608
|
+
let path4 = relative(from, file);
|
|
9609
|
+
this.memoizedPaths.set(file, path4);
|
|
9610
|
+
return path4;
|
|
9611
9611
|
}
|
|
9612
9612
|
previous() {
|
|
9613
9613
|
if (!this.previousMaps) {
|
|
@@ -9662,12 +9662,12 @@ var require_map_generator = __commonJS({
|
|
|
9662
9662
|
return window.btoa(unescape(encodeURIComponent(str3)));
|
|
9663
9663
|
}
|
|
9664
9664
|
}
|
|
9665
|
-
toFileUrl(
|
|
9666
|
-
let cached = this.memoizedFileURLs.get(
|
|
9665
|
+
toFileUrl(path4) {
|
|
9666
|
+
let cached = this.memoizedFileURLs.get(path4);
|
|
9667
9667
|
if (cached) return cached;
|
|
9668
9668
|
if (pathToFileURL) {
|
|
9669
|
-
let fileURL = pathToFileURL(
|
|
9670
|
-
this.memoizedFileURLs.set(
|
|
9669
|
+
let fileURL = pathToFileURL(path4).toString();
|
|
9670
|
+
this.memoizedFileURLs.set(path4, fileURL);
|
|
9671
9671
|
return fileURL;
|
|
9672
9672
|
} else {
|
|
9673
9673
|
throw new Error(
|
|
@@ -9675,14 +9675,14 @@ var require_map_generator = __commonJS({
|
|
|
9675
9675
|
);
|
|
9676
9676
|
}
|
|
9677
9677
|
}
|
|
9678
|
-
toUrl(
|
|
9679
|
-
let cached = this.memoizedURLs.get(
|
|
9678
|
+
toUrl(path4) {
|
|
9679
|
+
let cached = this.memoizedURLs.get(path4);
|
|
9680
9680
|
if (cached) return cached;
|
|
9681
9681
|
if (sep === "\\") {
|
|
9682
|
-
|
|
9682
|
+
path4 = path4.replace(/\\/g, "/");
|
|
9683
9683
|
}
|
|
9684
|
-
let url = encodeURI(
|
|
9685
|
-
this.memoizedURLs.set(
|
|
9684
|
+
let url = encodeURI(path4).replace(/[#?]/g, encodeURIComponent);
|
|
9685
|
+
this.memoizedURLs.set(path4, url);
|
|
9686
9686
|
return url;
|
|
9687
9687
|
}
|
|
9688
9688
|
};
|
|
@@ -16829,13 +16829,13 @@ function normalizeFiles(raw) {
|
|
|
16829
16829
|
const files = {};
|
|
16830
16830
|
if (!raw || typeof raw !== "object") return files;
|
|
16831
16831
|
let total = 0;
|
|
16832
|
-
for (const [
|
|
16832
|
+
for (const [path4, content] of Object.entries(raw)) {
|
|
16833
16833
|
if (Object.keys(files).length >= TEMPLATE_LIMITS.maxFiles) break;
|
|
16834
|
-
if (!FILE_PATH.test(
|
|
16834
|
+
if (!FILE_PATH.test(path4) || typeof content !== "string") continue;
|
|
16835
16835
|
if (Buffer.byteLength(content, "utf8") > TEMPLATE_LIMITS.maxFileBytes) continue;
|
|
16836
16836
|
total += Buffer.byteLength(content, "utf8");
|
|
16837
16837
|
if (total > TEMPLATE_LIMITS.maxTotalBytes) break;
|
|
16838
|
-
files[
|
|
16838
|
+
files[path4] = content;
|
|
16839
16839
|
}
|
|
16840
16840
|
return files;
|
|
16841
16841
|
}
|
|
@@ -16880,8 +16880,8 @@ var TEMPLATE_LIMITS2 = {
|
|
|
16880
16880
|
maxValuesDepth: 5
|
|
16881
16881
|
};
|
|
16882
16882
|
var FILE_PATH2 = /^(pages|layouts|components|styles|scripts)\/[a-z0-9][a-z0-9-_]{0,31}(\/[a-z0-9][a-z0-9-_]{0,31})?\.(liquid|css|js)$/;
|
|
16883
|
-
function isValidTemplatePath(
|
|
16884
|
-
return FILE_PATH2.test(
|
|
16883
|
+
function isValidTemplatePath(path4) {
|
|
16884
|
+
return FILE_PATH2.test(path4);
|
|
16885
16885
|
}
|
|
16886
16886
|
var FIELD_KEY2 = /^[a-z][a-z0-9_]{0,39}$/;
|
|
16887
16887
|
function byteLength(value) {
|
|
@@ -16941,13 +16941,13 @@ function normalizeFiles2(raw) {
|
|
|
16941
16941
|
const files = {};
|
|
16942
16942
|
if (!raw || typeof raw !== "object") return files;
|
|
16943
16943
|
let total = 0;
|
|
16944
|
-
for (const [
|
|
16944
|
+
for (const [path4, content] of Object.entries(raw)) {
|
|
16945
16945
|
if (Object.keys(files).length >= TEMPLATE_LIMITS2.maxFiles) break;
|
|
16946
|
-
if (!FILE_PATH2.test(
|
|
16946
|
+
if (!FILE_PATH2.test(path4) || typeof content !== "string") continue;
|
|
16947
16947
|
if (byteLength(content) > TEMPLATE_LIMITS2.maxFileBytes) continue;
|
|
16948
16948
|
total += byteLength(content);
|
|
16949
16949
|
if (total > TEMPLATE_LIMITS2.maxTotalBytes) break;
|
|
16950
|
-
files[
|
|
16950
|
+
files[path4] = content;
|
|
16951
16951
|
}
|
|
16952
16952
|
return files;
|
|
16953
16953
|
}
|
|
@@ -21120,7 +21120,7 @@ function createEngine(files) {
|
|
|
21120
21120
|
return engine;
|
|
21121
21121
|
}
|
|
21122
21122
|
function collectTemplateCss(template) {
|
|
21123
|
-
const css = Object.keys(template.files).filter((
|
|
21123
|
+
const css = Object.keys(template.files).filter((path4) => path4.startsWith("styles/") && path4.endsWith(".css")).sort().map((path4) => template.files[path4]).join("\n");
|
|
21124
21124
|
return sanitizeTemplateCss(css);
|
|
21125
21125
|
}
|
|
21126
21126
|
async function renderTemplatePage(template, page, context) {
|
|
@@ -21155,6 +21155,260 @@ function isTemplateBodyPage(value) {
|
|
|
21155
21155
|
return typeof value === "string" && TEMPLATE_BODY_PAGES.some((page) => page === value);
|
|
21156
21156
|
}
|
|
21157
21157
|
|
|
21158
|
+
// ../../site/src/lib/template/language-reference.ts
|
|
21159
|
+
var TEMPLATE_TAGS = [
|
|
21160
|
+
{
|
|
21161
|
+
name: "assign",
|
|
21162
|
+
description: "Atribui um valor a uma vari\xE1vel local.",
|
|
21163
|
+
example: '{% assign title = "Loja" %}{{ title }}'
|
|
21164
|
+
},
|
|
21165
|
+
{
|
|
21166
|
+
name: "capture",
|
|
21167
|
+
description: "Captura um bloco em texto.",
|
|
21168
|
+
example: "{% capture title %}Loja {{ year }}{% endcapture %}{{ title }}"
|
|
21169
|
+
},
|
|
21170
|
+
{
|
|
21171
|
+
name: "if",
|
|
21172
|
+
description: "Condi\xE7\xE3o com elsif e else; encerra com endif.",
|
|
21173
|
+
example: "{% if products.size > 0 %}Cat\xE1logo{% elsif store.name %}Loja{% else %}Vazio{% endif %}"
|
|
21174
|
+
},
|
|
21175
|
+
{
|
|
21176
|
+
name: "unless",
|
|
21177
|
+
description: "Condi\xE7\xE3o invertida, com else opcional.",
|
|
21178
|
+
example: "{% unless products.size == 0 %}Produtos{% else %}Vazio{% endunless %}"
|
|
21179
|
+
},
|
|
21180
|
+
{
|
|
21181
|
+
name: "case",
|
|
21182
|
+
description: "Seleciona um bloco when ou else.",
|
|
21183
|
+
example: '{% case page.kind %}{% when "index" %}In\xEDcio{% else %}Detalhe{% endcase %}'
|
|
21184
|
+
},
|
|
21185
|
+
{
|
|
21186
|
+
name: "for",
|
|
21187
|
+
description: "Itera listas ou intervalos. Suporta limit, offset, reversed, else e forloop.",
|
|
21188
|
+
example: "{% for n in (1..3) limit: 2 %}{{ forloop.index }}:{{ n }}{% else %}Vazio{% endfor %}"
|
|
21189
|
+
},
|
|
21190
|
+
{ name: "break", description: "Encerra o la\xE7o atual.", example: "{% for n in (1..3) %}{{ n }}{% break %}{% endfor %}" },
|
|
21191
|
+
{
|
|
21192
|
+
name: "continue",
|
|
21193
|
+
description: "Pula para a pr\xF3xima itera\xE7\xE3o.",
|
|
21194
|
+
example: "{% for n in (1..3) %}{% if n == 2 %}{% continue %}{% endif %}{{ n }}{% endfor %}"
|
|
21195
|
+
},
|
|
21196
|
+
{
|
|
21197
|
+
name: "cycle",
|
|
21198
|
+
description: "Alterna valores durante o la\xE7o; aceita grupo nomeado.",
|
|
21199
|
+
example: '{% for n in (1..3) %}{% cycle "par", "\xEDmpar" %}{% endfor %}'
|
|
21200
|
+
},
|
|
21201
|
+
{
|
|
21202
|
+
name: "increment",
|
|
21203
|
+
description: "Contador independente, come\xE7ando em zero.",
|
|
21204
|
+
example: "{% increment counter %}{% increment counter %}"
|
|
21205
|
+
},
|
|
21206
|
+
{
|
|
21207
|
+
name: "decrement",
|
|
21208
|
+
description: "Contador independente, come\xE7ando em menos um.",
|
|
21209
|
+
example: "{% decrement counter %}{% decrement counter %}"
|
|
21210
|
+
},
|
|
21211
|
+
{ name: "echo", description: "Exibe express\xE3o, com escape da sa\xEDda.", example: "{% echo store.name | upcase %}" },
|
|
21212
|
+
{
|
|
21213
|
+
name: "liquid",
|
|
21214
|
+
description: "Agrupa comandos, um por linha, sem delimitadores internos.",
|
|
21215
|
+
example: '{% liquid\nassign title = "Loja"\necho title\n%}'
|
|
21216
|
+
},
|
|
21217
|
+
{
|
|
21218
|
+
name: "comment",
|
|
21219
|
+
description: "Ignora o conte\xFAdo at\xE9 endcomment.",
|
|
21220
|
+
example: "{% comment %}Observa\xE7\xE3o interna{% endcomment %}Loja"
|
|
21221
|
+
},
|
|
21222
|
+
{ name: "#", description: "Coment\xE1rio em linha.", example: "{% # observa\xE7\xE3o %}Loja" },
|
|
21223
|
+
{
|
|
21224
|
+
name: "raw",
|
|
21225
|
+
description: "Exibe texto Liquid sem interpretar vari\xE1veis.",
|
|
21226
|
+
example: "{% raw %}{{ exemplo }}{% endraw %}"
|
|
21227
|
+
},
|
|
21228
|
+
{
|
|
21229
|
+
name: "render",
|
|
21230
|
+
description: "Renderiza arquivo do projeto em escopo isolado; aceita argumentos, with e for.",
|
|
21231
|
+
example: '{% render "components/reference", title: "Loja" %}'
|
|
21232
|
+
},
|
|
21233
|
+
{
|
|
21234
|
+
name: "include",
|
|
21235
|
+
description: "Inclui arquivo do projeto no escopo atual; prefira render para isolamento.",
|
|
21236
|
+
example: '{% include "components/reference" %}'
|
|
21237
|
+
},
|
|
21238
|
+
{
|
|
21239
|
+
name: "layout",
|
|
21240
|
+
description: "Aplica arquivo de layout com blocos nomeados.",
|
|
21241
|
+
example: '{% layout "layouts/reference" %}{% block content %}Loja{% endblock %}'
|
|
21242
|
+
},
|
|
21243
|
+
{
|
|
21244
|
+
name: "block",
|
|
21245
|
+
description: "Declara bloco substitu\xEDvel em um layout; block.super acessa o conte\xFAdo herdado.",
|
|
21246
|
+
example: "{% block content %}Loja{% endblock %}"
|
|
21247
|
+
},
|
|
21248
|
+
{
|
|
21249
|
+
name: "tablerow",
|
|
21250
|
+
description: "Produz linhas/c\xE9lulas HTML para uma lista; cols, limit, offset e tablerowloop.",
|
|
21251
|
+
example: "<table>{% tablerow n in (1..3) cols: 2 %}{{ n }}{% endtablerow %}</table>"
|
|
21252
|
+
}
|
|
21253
|
+
];
|
|
21254
|
+
var FILTER_ROWS = [
|
|
21255
|
+
["escape", "Escapa HTML.", '"<b>" | escape'],
|
|
21256
|
+
["xml_escape", "Escapa entidades XML.", '"<b>" | xml_escape'],
|
|
21257
|
+
["escape_once", "Escapa sem duplicar entidades existentes.", '"&<" | escape_once'],
|
|
21258
|
+
["newline_to_br", "Converte quebras de linha em br.", '"texto" | newline_to_br'],
|
|
21259
|
+
["strip_html", "Remove marca\xE7\xE3o HTML.", '"<b>Loja</b>" | strip_html'],
|
|
21260
|
+
["abs", "Valor absoluto.", "-3 | abs"],
|
|
21261
|
+
["at_least", "Aplica valor m\xEDnimo.", "2 | at_least: 3"],
|
|
21262
|
+
["at_most", "Aplica valor m\xE1ximo.", "5 | at_most: 3"],
|
|
21263
|
+
["ceil", "Arredonda para cima.", "2.2 | ceil"],
|
|
21264
|
+
["floor", "Arredonda para baixo.", "2.8 | floor"],
|
|
21265
|
+
["divided_by", "Divide pelo argumento.", "8 | divided_by: 2"],
|
|
21266
|
+
["minus", "Subtrai argumento.", "8 | minus: 2"],
|
|
21267
|
+
["plus", "Soma argumento.", "8 | plus: 2"],
|
|
21268
|
+
["modulo", "Resto da divis\xE3o.", "8 | modulo: 3"],
|
|
21269
|
+
["times", "Multiplica argumento.", "8 | times: 2"],
|
|
21270
|
+
["round", "Arredonda; argumento define casas decimais.", "2.567 | round: 2"],
|
|
21271
|
+
["url_decode", "Decodifica texto de URL.", '"a%20b" | url_decode'],
|
|
21272
|
+
["url_encode", "Codifica texto de URL.", '"a b" | url_encode'],
|
|
21273
|
+
["cgi_escape", "Codifica texto para query CGI.", '"a b" | cgi_escape'],
|
|
21274
|
+
["uri_escape", "Escapa caracteres n\xE3o seguros de URI.", '"a b" | uri_escape'],
|
|
21275
|
+
[
|
|
21276
|
+
"slugify",
|
|
21277
|
+
"Vers\xE3o CeuPay: remove acentos, converte para min\xFAsculas e separa palavras com h\xEDfen.",
|
|
21278
|
+
'"C\xE9u Azul" | slugify'
|
|
21279
|
+
],
|
|
21280
|
+
["join", "Une lista com separador.", '"a,b" | split: "," | join: " / "'],
|
|
21281
|
+
["first", "Primeiro elemento.", '"a,b" | split: "," | first'],
|
|
21282
|
+
["last", "\xDAltimo elemento.", '"a,b" | split: "," | last'],
|
|
21283
|
+
["reverse", "Inverte lista.", '"a,b" | split: "," | reverse | join: ","'],
|
|
21284
|
+
["sort", "Ordena lista; argumento opcional seleciona propriedade.", '"b,a" | split: "," | sort | join: ","'],
|
|
21285
|
+
["sort_natural", "Ordena ignorando caixa.", '"b,A" | split: "," | sort_natural | join: ","'],
|
|
21286
|
+
["size", "Tamanho de texto/lista.", '"Loja" | size'],
|
|
21287
|
+
["map", "Extrai propriedade de cada item.", 'products | map: "name" | join: ","'],
|
|
21288
|
+
["sum", "Soma valores ou propriedade num\xE9rica.", 'products | sum: "price_cents"'],
|
|
21289
|
+
["compact", "Remove valores nulos; aceita propriedade.", 'products | map: "name" | compact | size'],
|
|
21290
|
+
["concat", "Combina duas listas.", "products | concat: products | size"],
|
|
21291
|
+
["push", "Acrescenta um item ao fim de uma c\xF3pia.", '"a,b" | split: "," | push: "c" | join: ","'],
|
|
21292
|
+
["unshift", "Acrescenta um item ao in\xEDcio de uma c\xF3pia.", '"a,b" | split: "," | unshift: "c" | join: ","'],
|
|
21293
|
+
["pop", "Remove o \xFAltimo item de uma c\xF3pia.", '"a,b" | split: "," | pop | join: ","'],
|
|
21294
|
+
["shift", "Remove o primeiro item de uma c\xF3pia.", '"a,b" | split: "," | shift | join: ","'],
|
|
21295
|
+
["slice", "Seleciona trecho por \xEDndice e tamanho.", '"Loja" | slice: 0, 2'],
|
|
21296
|
+
["where", "Seleciona itens por propriedade e valor.", 'products | where: "in_stock", true | size'],
|
|
21297
|
+
["reject", "Exclui itens por propriedade e valor.", 'products | reject: "in_stock", false | size'],
|
|
21298
|
+
["where_exp", "Seleciona por express\xE3o Liquid.", 'products | where_exp: "p", "p.price_cents > 0" | size'],
|
|
21299
|
+
["reject_exp", "Exclui por express\xE3o Liquid.", 'products | reject_exp: "p", "p.price_cents == 0" | size'],
|
|
21300
|
+
["group_by", "Agrupa por propriedade; itens exp\xF5em name/items.", 'products | group_by: "category" | size'],
|
|
21301
|
+
["group_by_exp", "Agrupa pelo resultado de express\xE3o.", 'products | group_by_exp: "p", "p.category" | size'],
|
|
21302
|
+
["has", "Verifica se existe item com propriedade e valor.", 'products | has: "in_stock", true'],
|
|
21303
|
+
["has_exp", "Verifica exist\xEAncia por express\xE3o.", 'products | has_exp: "p", "p.price_cents > 0"'],
|
|
21304
|
+
["find_index", "\xCDndice do primeiro item com propriedade e valor.", 'products | find_index: "in_stock", true'],
|
|
21305
|
+
["find_index_exp", "\xCDndice do primeiro item que atende express\xE3o.", 'products | find_index_exp: "p", "p.price_cents > 0"'],
|
|
21306
|
+
["find", "Primeiro item com propriedade e valor.", 'products | find: "in_stock", true | json'],
|
|
21307
|
+
["find_exp", "Primeiro item que atende express\xE3o.", 'products | find_exp: "p", "p.price_cents > 0" | json'],
|
|
21308
|
+
["uniq", "Remove duplicatas; aceita propriedade.", '"a,a,b" | split: "," | uniq | join: ","'],
|
|
21309
|
+
["sample", "Amostra aleat\xF3ria; n\xE3o use em decis\xF5es de pre\xE7o ou entrega.", '"a,b" | split: "," | sample'],
|
|
21310
|
+
["date", "Formata data usando marcadores strftime.", '"2026-10-29" | date: "%d/%m/%Y"'],
|
|
21311
|
+
["date_to_xmlschema", "Formata data ISO/XML.", '"2026-10-29" | date_to_xmlschema'],
|
|
21312
|
+
["date_to_rfc822", "Formata data RFC822.", '"2026-10-29" | date_to_rfc822'],
|
|
21313
|
+
["date_to_string", "Data curta leg\xEDvel.", '"2026-10-29" | date_to_string'],
|
|
21314
|
+
["date_to_long_string", "Data longa leg\xEDvel.", '"2026-10-29" | date_to_long_string'],
|
|
21315
|
+
["append", "Acrescenta texto ao fim.", '"Loja" | append: " CeuPay"'],
|
|
21316
|
+
["prepend", "Acrescenta texto ao in\xEDcio.", '"Loja" | prepend: "Minha "'],
|
|
21317
|
+
["lstrip", "Remove espa\xE7o \xE0 esquerda.", '" Loja " | lstrip'],
|
|
21318
|
+
["rstrip", "Remove espa\xE7o \xE0 direita.", '" Loja " | rstrip'],
|
|
21319
|
+
["strip", "Remove espa\xE7o nas extremidades.", '" Loja " | strip'],
|
|
21320
|
+
["downcase", "Converte para min\xFAsculas.", '"LOJA" | downcase'],
|
|
21321
|
+
["upcase", "Converte para mai\xFAsculas.", '"loja" | upcase'],
|
|
21322
|
+
["remove", "Remove todas as ocorr\xEAncias.", '"abcabc" | remove: "a"'],
|
|
21323
|
+
["remove_first", "Remove a primeira ocorr\xEAncia.", '"abcabc" | remove_first: "a"'],
|
|
21324
|
+
["remove_last", "Remove a \xFAltima ocorr\xEAncia.", '"abcabc" | remove_last: "a"'],
|
|
21325
|
+
["split", "Divide texto em lista.", '"a,b" | split: "," | size'],
|
|
21326
|
+
["strip_newlines", "Remove quebras de linha.", '"Loja" | strip_newlines'],
|
|
21327
|
+
["squish", "Compacta espa\xE7os e remove extremidades.", '" a b " | squish'],
|
|
21328
|
+
["capitalize", "Inicial mai\xFAscula e restante min\xFAsculo.", '"loja" | capitalize'],
|
|
21329
|
+
["replace", "Substitui todas as ocorr\xEAncias.", '"abcabc" | replace: "a", "x"'],
|
|
21330
|
+
["replace_first", "Substitui a primeira ocorr\xEAncia.", '"abcabc" | replace_first: "a", "x"'],
|
|
21331
|
+
["replace_last", "Substitui a \xFAltima ocorr\xEAncia.", '"abcabc" | replace_last: "a", "x"'],
|
|
21332
|
+
["truncate", "Limita caracteres; aceita sufixo.", '"Loja CeuPay" | truncate: 7, "\u2026"'],
|
|
21333
|
+
["truncatewords", "Limita palavras; aceita sufixo.", '"Minha Loja CeuPay" | truncatewords: 2'],
|
|
21334
|
+
["normalize_whitespace", "Normaliza espa\xE7os.", '"a b" | normalize_whitespace'],
|
|
21335
|
+
["number_of_words", "Conta palavras.", '"Minha loja" | number_of_words'],
|
|
21336
|
+
["array_to_sentence_string", "Formata lista como frase.", '"a,b,c" | split: "," | array_to_sentence_string'],
|
|
21337
|
+
["base64_encode", "Codifica texto em Base64; n\xE3o protege segredos.", '"Loja" | base64_encode'],
|
|
21338
|
+
["base64_decode", "Decodifica Base64.", '"TG9qYQ==" | base64_decode'],
|
|
21339
|
+
["sha256", "Hash SHA-256 de texto p\xFAblico.", '"Loja" | sha256'],
|
|
21340
|
+
[
|
|
21341
|
+
"hmac_sha256",
|
|
21342
|
+
"HMAC de texto com chave expl\xEDcita fict\xEDcia; nunca forne\xE7a credenciais ao contexto.",
|
|
21343
|
+
'"Loja" | hmac_sha256: "exemplo-publico"'
|
|
21344
|
+
],
|
|
21345
|
+
["default", "Fallback para null, false ou vazio; allow_false preserva false.", '"" | default: "Loja"'],
|
|
21346
|
+
["raw", "Pula escape da sa\xEDda Liquid; a sanitiza\xE7\xE3o HTML final continua obrigat\xF3ria.", '"<b>Loja</b>" | raw'],
|
|
21347
|
+
["jsonify", "Serializa para JSON.", "products | jsonify"],
|
|
21348
|
+
["json", "Serializa para JSON, equivalente a jsonify.", "products | json"],
|
|
21349
|
+
["inspect", "Representa\xE7\xE3o JSON para depura\xE7\xE3o de dados p\xFAblicos.", "products | inspect"],
|
|
21350
|
+
["to_integer", "Converte para inteiro.", '"12" | to_integer']
|
|
21351
|
+
];
|
|
21352
|
+
var TEMPLATE_FILTERS = FILTER_ROWS.map(([name, description, expression]) => ({
|
|
21353
|
+
name,
|
|
21354
|
+
description,
|
|
21355
|
+
example: `{{ ${expression} }}`
|
|
21356
|
+
}));
|
|
21357
|
+
|
|
21358
|
+
// src/reference.ts
|
|
21359
|
+
var agentInstructions = `# CeuPay store template
|
|
21360
|
+
|
|
21361
|
+
Read CEUPAY-REFERENCE.md before editing. This project belongs to one authorized store.
|
|
21362
|
+
Edit ceupay-template.json and pages/, layouts/, components/, styles/, scripts/ only.
|
|
21363
|
+
Use standard Liquid {{ output }} and {% tag %}. Never invent globals or a load tag.
|
|
21364
|
+
Use npx @ceupay/template-cli@alpha validate . and serve . for interactive fictitious-data preview.
|
|
21365
|
+
No credentials belong in this project, browser code, commits, prompts or generated documentation.
|
|
21366
|
+
Do not read environment secrets. The merchant pastes the short-lived session into the CLI terminal.
|
|
21367
|
+
The --watch --yes mode publishes valid saved changes to the live store: tell the merchant before saving edits.
|
|
21368
|
+
Do not start remote publication, replay, restoration or synchronization without the merchant's authorization.
|
|
21369
|
+
Preserve .ceupay-remote.json, locks and .ceupay-operations/; never edit or delete operation receipts to bypass conflicts.
|
|
21370
|
+
On uncertainty stop; recover the SAME operation with replay and pull a fresh folder before continuing.
|
|
21371
|
+
Run no seller JavaScript in Node. Seller scripts execute only in the opaque browser preview iframe.
|
|
21372
|
+
Checkout, identity, stock and payment authority remain on the platform.
|
|
21373
|
+
Full references: https://froghub.com.br/docs/templates-referencia
|
|
21374
|
+
`;
|
|
21375
|
+
var templateReference = `# CeuPay template reference
|
|
21376
|
+
|
|
21377
|
+
Files: ceupay-template.json (format ceupay-template-project, formatVersion 1, template metadata without files).
|
|
21378
|
+
Metadata: name, baseId (string|null), version, schema.groups, values.
|
|
21379
|
+
Code directories: pages, layouts, components, styles, scripts. Maximum 40 files, 100000 bytes/file, 400000 bytes total.
|
|
21380
|
+
One optional subdirectory; segments are lowercase letters/numbers/hyphen/underscore, at most 32 characters.
|
|
21381
|
+
Required page: pages/index.liquid. Optional pages: catalog, product, post. Header/footer: components/header.liquid and footer.liquid.
|
|
21382
|
+
HTML is sanitized; CSS is scoped; scripts/*.js are classic scripts, isolated with sandbox=allow-scripts, never allow-same-origin.
|
|
21383
|
+
window.ceupay.navigate(href), addToCart(productId, quantity) are validated bridges; local preview SIMULATES these actions.
|
|
21384
|
+
|
|
21385
|
+
Globals: store{name,slug,tagline,description,logo_url,banner_url,server_ip,initial,social{discord,youtube,instagram,tiktok,wiki},texts,show_reviews,show_news,show_online_players}; settings; products[]; categories[{name,slug,anchor,count,products}]; reviews[{rating,comment,author}]; news[{id,title,summary,published_at,url}]; players{online,reporting_servers,observed_at,valid_until}; connections[{label,platform,host,port,address,key,button_label}]; stats{products_count,categories_count,reviews_count,reviews_average,cheapest_price}; urls{home,products,catalog?,cart,checkout,account}; year; page.kind.
|
|
21386
|
+
Product: id,name,slug,url,description,image_url,images,type,category,price(formatted),price_cents(number),in_stock,available_count(null=unlimited/unknown),stock_mode?,has_variants?,variants?,benefits[].
|
|
21387
|
+
Product page: product. Post page: post{id,title,summary,body,published_at,url}. Catalog: catalog{search,page,total_pages,total,previous_url,next_url}; products is filtered/paginated. Other detail globals are null.
|
|
21388
|
+
Schema: groups[{title,fields[]}]; field{key,label,type,description,default,options:[{value,label}],fields:[],max:null|number}.
|
|
21389
|
+
Types: text,textarea,url,number,color,toggle,select,image,richtext,array,packages. packages resolves selected public products. array uses nested fields.
|
|
21390
|
+
Keys: lowercase initial letter, lowercase letters/numbers/underscore, max40 chars, unique. Max30 groups/40 fields per group/50 select options/100 array or package selections. Values max120000 bytes/depth5.
|
|
21391
|
+
No private orders, payment data, credentials or arbitrary entity loading. Missing values are empty; unknown filters are no-ops, not extra features. Empty arrays/strings are truthy in Liquid; test size or blank. Only false and nil are falsy.
|
|
21392
|
+
Operators: == != > < >= <= contains and or. Use assign instead of unsupported parentheses in conditions. Whitespace trim: {{- value -}} and {%- tag -%}.
|
|
21393
|
+
Limits: render CPU2500ms, memory64000000, parse600000; in-memory project partials only. Prefer explicit names with render.
|
|
21394
|
+
|
|
21395
|
+
## Tags
|
|
21396
|
+
${TEMPLATE_TAGS.map((row) => `### ${row.name}
|
|
21397
|
+
${row.description}
|
|
21398
|
+
|
|
21399
|
+
\`\`\`liquid
|
|
21400
|
+
${row.example}
|
|
21401
|
+
\`\`\``).join("\n\n")}
|
|
21402
|
+
|
|
21403
|
+
## Filters
|
|
21404
|
+
${TEMPLATE_FILTERS.map((row) => `### ${row.name}
|
|
21405
|
+
${row.description}
|
|
21406
|
+
|
|
21407
|
+
\`\`\`liquid
|
|
21408
|
+
${row.example}
|
|
21409
|
+
\`\`\``).join("\n\n")}
|
|
21410
|
+
`;
|
|
21411
|
+
|
|
21158
21412
|
// src/project.ts
|
|
21159
21413
|
var ProjectError = class extends Error {
|
|
21160
21414
|
};
|
|
@@ -21288,6 +21542,14 @@ async function createProject(directory, template) {
|
|
|
21288
21542
|
await import_promises.default.mkdir(import_node_path.default.dirname(target2), { recursive: true, mode: 448 });
|
|
21289
21543
|
await import_promises.default.writeFile(target2, contents, { flag: "wx", mode: 384 });
|
|
21290
21544
|
}
|
|
21545
|
+
for (const [file, contents] of Object.entries({
|
|
21546
|
+
"AGENTS.md": agentInstructions,
|
|
21547
|
+
"CLAUDE.md": agentInstructions,
|
|
21548
|
+
"CEUPAY-REFERENCE.md": templateReference,
|
|
21549
|
+
".gitignore": ".ceupay-remote*\n.ceupay-operations/\n.env*\n"
|
|
21550
|
+
})) {
|
|
21551
|
+
await import_promises.default.writeFile(import_node_path.default.join(root, file), contents, { flag: "wx", mode: 384 });
|
|
21552
|
+
}
|
|
21291
21553
|
}
|
|
21292
21554
|
async function initialize(baseId, directory) {
|
|
21293
21555
|
const template = cloneBaseTemplate(baseId);
|
|
@@ -21924,9 +22186,16 @@ async function boundedFetch(request) {
|
|
|
21924
22186
|
function connection(options) {
|
|
21925
22187
|
if (process.env.NODE_TLS_REJECT_UNAUTHORIZED === "0") return fail2("A verifica\xE7\xE3o TLS precisa estar ativa.");
|
|
21926
22188
|
const apiOrigin = origin(options["api-origin"] ?? process.env.CEUPAY_API_ORIGIN ?? "https://froghub.com.br");
|
|
21927
|
-
const key = process.env.CEUPAY_API_KEY;
|
|
22189
|
+
const key = process.env.CEUPAY_EDITOR_TOKEN ?? process.env.CEUPAY_API_KEY;
|
|
21928
22190
|
try {
|
|
21929
|
-
return {
|
|
22191
|
+
return {
|
|
22192
|
+
client: createCeuPayClient({
|
|
22193
|
+
apiOrigin,
|
|
22194
|
+
apiKey: key ?? "",
|
|
22195
|
+
fetch: boundedFetch
|
|
22196
|
+
}),
|
|
22197
|
+
apiOrigin
|
|
22198
|
+
};
|
|
21930
22199
|
} catch {
|
|
21931
22200
|
return fail2("Configure CEUPAY_API_KEY no ambiente; n\xE3o use a chave como argumento.");
|
|
21932
22201
|
}
|
|
@@ -21980,11 +22249,14 @@ async function current(client, storeId) {
|
|
|
21980
22249
|
async function historical(client, storeId, selected) {
|
|
21981
22250
|
const value = snapshot(
|
|
21982
22251
|
await network(
|
|
21983
|
-
async () => result(
|
|
22252
|
+
async () => result(
|
|
22253
|
+
await client.GET("/v1/templates/history/{revision}", {
|
|
22254
|
+
params: { path: { revision: selected } }
|
|
22255
|
+
})
|
|
22256
|
+
)
|
|
21984
22257
|
)
|
|
21985
22258
|
);
|
|
21986
|
-
if (value.storeId !== storeId || value.revision !== selected)
|
|
21987
|
-
return fail2("Vers\xE3o hist\xF3rica de outra loja ou revis\xE3o.");
|
|
22259
|
+
if (value.storeId !== storeId || value.revision !== selected) return fail2("Vers\xE3o hist\xF3rica de outra loja ou revis\xE3o.");
|
|
21988
22260
|
return value;
|
|
21989
22261
|
}
|
|
21990
22262
|
function bind(apiOrigin, head) {
|
|
@@ -22018,21 +22290,11 @@ function checkOrigin(actual, configured) {
|
|
|
22018
22290
|
function target(options, saved) {
|
|
22019
22291
|
const selected = options.store ?? saved?.storeId;
|
|
22020
22292
|
if (!uuid(selected)) return fail2("Informe --store com o UUID da loja para um projeto ainda sem v\xEDnculo.");
|
|
22021
|
-
if (saved && saved.storeId.toLowerCase() !== selected.toLowerCase())
|
|
22022
|
-
return fail2("O projeto est\xE1 vinculado a outra loja.");
|
|
22293
|
+
if (saved && saved.storeId.toLowerCase() !== selected.toLowerCase()) return fail2("O projeto est\xE1 vinculado a outra loja.");
|
|
22023
22294
|
return selected.toLowerCase();
|
|
22024
22295
|
}
|
|
22025
22296
|
function operation(raw) {
|
|
22026
|
-
if (!record2(raw) || !exact(raw, [
|
|
22027
|
-
"format",
|
|
22028
|
-
"formatVersion",
|
|
22029
|
-
"apiOrigin",
|
|
22030
|
-
"storeId",
|
|
22031
|
-
"kind",
|
|
22032
|
-
"templateHash",
|
|
22033
|
-
"sourceChecksum",
|
|
22034
|
-
"request"
|
|
22035
|
-
]) || raw.format !== "ceupay-template-operation" || raw.formatVersion !== 1 || !uuid(raw.storeId) || origin(raw.apiOrigin) !== raw.apiOrigin || !record2(raw.request))
|
|
22297
|
+
if (!record2(raw) || !exact(raw, ["format", "formatVersion", "apiOrigin", "storeId", "kind", "templateHash", "sourceChecksum", "request"]) || raw.format !== "ceupay-template-operation" || raw.formatVersion !== 1 || !uuid(raw.storeId) || origin(raw.apiOrigin) !== raw.apiOrigin || !record2(raw.request))
|
|
22036
22298
|
return fail2("Arquivo da opera\xE7\xE3o inv\xE1lido.");
|
|
22037
22299
|
const request = raw.request, kind = raw.kind;
|
|
22038
22300
|
if (kind !== "PUBLISH" && kind !== "RESTORE" || !exact(request, [
|
|
@@ -22049,8 +22311,7 @@ function operation(raw) {
|
|
|
22049
22311
|
checkedTemplate(request.template);
|
|
22050
22312
|
} else if (!revision(request.sourceRevision) || !checksum(raw.sourceChecksum) || raw.templateHash !== null)
|
|
22051
22313
|
return fail2("Restaura\xE7\xE3o inv\xE1lida.");
|
|
22052
|
-
if (Buffer.byteLength(JSON.stringify(request), "utf8") > 600 * 1024)
|
|
22053
|
-
return fail2("O corpo da opera\xE7\xE3o excede 600 KiB.");
|
|
22314
|
+
if (Buffer.byteLength(JSON.stringify(request), "utf8") > 600 * 1024) return fail2("O corpo da opera\xE7\xE3o excede 600 KiB.");
|
|
22054
22315
|
return raw;
|
|
22055
22316
|
}
|
|
22056
22317
|
async function saveOperation(file, value) {
|
|
@@ -22069,12 +22330,15 @@ async function apply(client, value) {
|
|
|
22069
22330
|
await current(client, value.storeId);
|
|
22070
22331
|
if (value.kind === "RESTORE") {
|
|
22071
22332
|
const source = await historical(client, value.storeId, value.request.sourceRevision);
|
|
22072
|
-
if (source.checksum !== value.sourceChecksum)
|
|
22073
|
-
return fail2("O snapshot hist\xF3rico mudou; revis\xE3o do operador necess\xE1ria.");
|
|
22333
|
+
if (source.checksum !== value.sourceChecksum) return fail2("O snapshot hist\xF3rico mudou; revis\xE3o do operador necess\xE1ria.");
|
|
22074
22334
|
}
|
|
22075
22335
|
const raw = await network(
|
|
22076
22336
|
async () => result(
|
|
22077
|
-
value.kind === "PUBLISH" ? await client.POST("/v1/templates/publications", {
|
|
22337
|
+
value.kind === "PUBLISH" ? await client.POST("/v1/templates/publications", {
|
|
22338
|
+
body: value.request
|
|
22339
|
+
}) : await client.POST("/v1/templates/restorations", {
|
|
22340
|
+
body: value.request
|
|
22341
|
+
})
|
|
22078
22342
|
),
|
|
22079
22343
|
true
|
|
22080
22344
|
);
|
|
@@ -22140,6 +22404,7 @@ async function publishProject(directory, value, client, apiOrigin) {
|
|
|
22140
22404
|
console.error(
|
|
22141
22405
|
"Opera\xE7\xE3o confirmada; v\xEDnculo local n\xE3o atualizado. Baixe o tema atual em outra pasta e revise suas altera\xE7\xF5es."
|
|
22142
22406
|
);
|
|
22407
|
+
return updated;
|
|
22143
22408
|
} finally {
|
|
22144
22409
|
await handle.close().catch(() => void 0);
|
|
22145
22410
|
try {
|
|
@@ -22187,20 +22452,35 @@ async function runRemote(command, args) {
|
|
|
22187
22452
|
if (limit < 1 || limit > 50) return fail2("Quantidade deve ser de 1 a 50.");
|
|
22188
22453
|
const beforeRevision = options.before === void 0 ? void 0 : integer(options.before, "Revis\xE3o");
|
|
22189
22454
|
const page = await network(
|
|
22190
|
-
async () => result(
|
|
22455
|
+
async () => result(
|
|
22456
|
+
await client.GET("/v1/templates/history", {
|
|
22457
|
+
params: { query: { limit, beforeRevision } }
|
|
22458
|
+
})
|
|
22459
|
+
)
|
|
22191
22460
|
);
|
|
22192
22461
|
if (!record2(page) || !Array.isArray(page.data) || page.data.length > limit || page.nextRevision !== null && !revision(page.nextRevision))
|
|
22193
22462
|
return fail2("Hist\xF3rico inv\xE1lido.");
|
|
22194
22463
|
const rows = page.data.map((value2) => {
|
|
22195
22464
|
if (!record2(value2) || !revision(value2.revision) || !checksum(value2.checksum) || value2.origin !== "BASELINE" && value2.origin !== "WRITE" || typeof value2.createdAt !== "string" || !Number.isFinite(Date.parse(value2.createdAt)))
|
|
22196
22465
|
return fail2("Metadados do hist\xF3rico inv\xE1lidos.");
|
|
22197
|
-
return {
|
|
22466
|
+
return {
|
|
22467
|
+
revision: value2.revision,
|
|
22468
|
+
checksum: value2.checksum,
|
|
22469
|
+
origin: value2.origin,
|
|
22470
|
+
createdAt: value2.createdAt
|
|
22471
|
+
};
|
|
22198
22472
|
});
|
|
22199
22473
|
if (rows.some(
|
|
22200
22474
|
(value2, index) => beforeRevision !== void 0 && value2.revision >= beforeRevision || index > 0 && rows[index - 1].revision <= value2.revision
|
|
22201
22475
|
) || page.nextRevision !== null && page.nextRevision !== rows.at(-1)?.revision)
|
|
22202
22476
|
return fail2("Pagina\xE7\xE3o do hist\xF3rico inconsistente.");
|
|
22203
|
-
console.log(
|
|
22477
|
+
console.log(
|
|
22478
|
+
json({
|
|
22479
|
+
storeId: head.storeId,
|
|
22480
|
+
data: rows,
|
|
22481
|
+
nextRevision: page.nextRevision
|
|
22482
|
+
}).trim()
|
|
22483
|
+
);
|
|
22204
22484
|
return;
|
|
22205
22485
|
}
|
|
22206
22486
|
if (command === "prepare-publish") {
|
|
@@ -22242,16 +22522,279 @@ async function runRemote(command, args) {
|
|
|
22242
22522
|
checkOrigin(value.apiOrigin, apiOrigin);
|
|
22243
22523
|
if (command === "publish") {
|
|
22244
22524
|
if (value.kind !== "PUBLISH") return fail2("Use restore para uma opera\xE7\xE3o de restaura\xE7\xE3o.");
|
|
22245
|
-
|
|
22246
|
-
return;
|
|
22525
|
+
return publishProject(first, value, client, apiOrigin);
|
|
22247
22526
|
}
|
|
22248
22527
|
if (command === "restore" && value.kind !== "RESTORE") return fail2("Use publish ou replay para uma publica\xE7\xE3o.");
|
|
22249
22528
|
console.log(json(receipt(await apply(client, value))).trim());
|
|
22250
22529
|
}
|
|
22530
|
+
async function remoteMatchesProject(directory) {
|
|
22531
|
+
const root = await privateRoot(directory), saved = await binding(root);
|
|
22532
|
+
if (!saved) return fail2("O projeto precisa ser baixado com pull antes da sincroniza\xE7\xE3o.");
|
|
22533
|
+
const { client, apiOrigin } = connection({});
|
|
22534
|
+
checkOrigin(saved.apiOrigin, apiOrigin);
|
|
22535
|
+
const head = await current(client, saved.storeId);
|
|
22536
|
+
if (saved.revision !== head.revision || saved.checksum !== head.checksum)
|
|
22537
|
+
return fail2("O tema mudou na loja. Baixe uma pasta nova e revise as altera\xE7\xF5es.");
|
|
22538
|
+
if (!head.theme?.template) return false;
|
|
22539
|
+
return digest({ ...await loadProject(root), version: 1 }) === digest({ ...checkedTemplate(head.theme.template), version: 1 });
|
|
22540
|
+
}
|
|
22541
|
+
|
|
22542
|
+
// src/local.ts
|
|
22543
|
+
var import_promises3 = __toESM(require("node:fs/promises"), 1);
|
|
22544
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
22545
|
+
var import_node_http = __toESM(require("node:http"), 1);
|
|
22546
|
+
var import_node_crypto2 = require("node:crypto");
|
|
22547
|
+
var import_promises4 = require("node:timers/promises");
|
|
22548
|
+
|
|
22549
|
+
// ../../site/src/lib/template/sandbox-doc.ts
|
|
22550
|
+
function collectTemplateScripts(template) {
|
|
22551
|
+
return Object.keys(template.files).filter((path4) => path4.startsWith("scripts/") && path4.endsWith(".js")).sort().map((path4) => `// ${path4}
|
|
22552
|
+
${template.files[path4]}`).join("\n;\n");
|
|
22553
|
+
}
|
|
22554
|
+
var BRIDGE = `
|
|
22555
|
+
(function () {
|
|
22556
|
+
var send = function (message) { parent.postMessage(Object.assign({ source: 'ceupay-template' }, message), '*'); };
|
|
22557
|
+
window.ceupay = {
|
|
22558
|
+
addToCart: function (productId, quantity) { send({ type: 'addToCart', productId: String(productId), quantity: Number(quantity) || 1 }); },
|
|
22559
|
+
navigate: function (href) { send({ type: 'navigate', href: String(href) }); }
|
|
22560
|
+
};
|
|
22561
|
+
document.addEventListener('click', function (event) {
|
|
22562
|
+
var link = event.target && event.target.closest ? event.target.closest('a[href]') : null;
|
|
22563
|
+
if (!link) return;
|
|
22564
|
+
var href = link.getAttribute('href') || '';
|
|
22565
|
+
if (href.charAt(0) === '#') return;
|
|
22566
|
+
event.preventDefault();
|
|
22567
|
+
send({ type: 'navigate', href: href, blank: link.getAttribute('target') === '_blank' });
|
|
22568
|
+
});
|
|
22569
|
+
var report = function () { send({ type: 'resize', height: Math.ceil(document.documentElement.scrollHeight) }); };
|
|
22570
|
+
new ResizeObserver(report).observe(document.documentElement);
|
|
22571
|
+
window.addEventListener('load', report);
|
|
22572
|
+
})();
|
|
22573
|
+
`;
|
|
22574
|
+
function escapeScript(code) {
|
|
22575
|
+
return code.replaceAll("</script", "<\\/script").replaceAll("<!--", "<\\!--");
|
|
22576
|
+
}
|
|
22577
|
+
function escapeAttribute2(value) {
|
|
22578
|
+
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<");
|
|
22579
|
+
}
|
|
22580
|
+
function buildSandboxDocument({
|
|
22581
|
+
template,
|
|
22582
|
+
html,
|
|
22583
|
+
wrapperStyle,
|
|
22584
|
+
nonce,
|
|
22585
|
+
page = "pages/index"
|
|
22586
|
+
}) {
|
|
22587
|
+
const css = collectTemplateCss(template);
|
|
22588
|
+
const scripts = escapeScript(collectTemplateScripts(template));
|
|
22589
|
+
const safeNonce = escapeAttribute2(nonce);
|
|
22590
|
+
return `<!doctype html><html lang="pt-BR"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><base target="_blank"><style>html,body{margin:0;overflow:hidden;background:transparent;color:#fff;font-family:system-ui,sans-serif}</style><style>${css}</style></head><body><div data-store-template data-template-page="${escapeAttribute2(page)}" style="${escapeAttribute2(wrapperStyle)}">${html}</div><script nonce="${safeNonce}">${BRIDGE}</script><script nonce="${safeNonce}">try{${scripts}
|
|
22591
|
+
}catch(e){console.error(e)}</script></body></html>`;
|
|
22592
|
+
}
|
|
22593
|
+
|
|
22594
|
+
// src/local.ts
|
|
22595
|
+
var hash = (value) => (0, import_node_crypto2.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
22596
|
+
var escape3 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll('"', """);
|
|
22597
|
+
async function sessionSecret() {
|
|
22598
|
+
if (process.env.CEUPAY_EDITOR_TOKEN) return process.env.CEUPAY_EDITOR_TOKEN;
|
|
22599
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
22600
|
+
throw new ProjectError("Configure CEUPAY_EDITOR_TOKEN ou use um terminal interativo.");
|
|
22601
|
+
process.stdout.write("Cole a sess\xE3o criada no painel (entrada oculta): ");
|
|
22602
|
+
return new Promise((resolve, reject2) => {
|
|
22603
|
+
let value = "";
|
|
22604
|
+
const previous = process.stdin.isRaw;
|
|
22605
|
+
process.stdin.setRawMode(true);
|
|
22606
|
+
process.stdin.resume();
|
|
22607
|
+
process.stdin.setEncoding("utf8");
|
|
22608
|
+
const finish = () => {
|
|
22609
|
+
process.stdin.off("data", receive);
|
|
22610
|
+
process.stdin.setRawMode(previous);
|
|
22611
|
+
process.stdin.pause();
|
|
22612
|
+
process.stdout.write("\n");
|
|
22613
|
+
};
|
|
22614
|
+
const receive = (chunk) => {
|
|
22615
|
+
for (const character of chunk) {
|
|
22616
|
+
if (character === "") {
|
|
22617
|
+
finish();
|
|
22618
|
+
reject2(new ProjectError("Edi\xE7\xE3o cancelada."));
|
|
22619
|
+
return;
|
|
22620
|
+
}
|
|
22621
|
+
if (character === "\r" || character === "\n") {
|
|
22622
|
+
finish();
|
|
22623
|
+
if (!/^cc_prod_[a-f0-9]{64}$/.test(value)) reject2(new ProjectError("Sess\xE3o inv\xE1lida."));
|
|
22624
|
+
else resolve(value);
|
|
22625
|
+
return;
|
|
22626
|
+
}
|
|
22627
|
+
if (character === "\x7F" || character === "\b") value = value.slice(0, -1);
|
|
22628
|
+
else if (value.length < 80 && /[a-z0-9_]/i.test(character)) value += character;
|
|
22629
|
+
}
|
|
22630
|
+
};
|
|
22631
|
+
process.stdin.on("data", receive);
|
|
22632
|
+
});
|
|
22633
|
+
}
|
|
22634
|
+
async function previewDocument(directory, page = "index") {
|
|
22635
|
+
if (!["index", "catalog", "product", "post"].includes(page)) throw new ProjectError("P\xE1gina inv\xE1lida.");
|
|
22636
|
+
const template = await loadProject(directory);
|
|
22637
|
+
const demo = findBaseDemo(template.baseId ?? "fogueira") ?? findBaseDemo("fogueira");
|
|
22638
|
+
if (!demo) throw new ProjectError("Cat\xE1logo de exemplo indispon\xEDvel.");
|
|
22639
|
+
const selected = `pages/${page}`;
|
|
22640
|
+
if (!template.files[selected + ".liquid"]) throw new ProjectError("P\xE1gina ausente no projeto.");
|
|
22641
|
+
const context = buildDemoContext(template, demo.demo, "/", selected);
|
|
22642
|
+
const html = [];
|
|
22643
|
+
for (const file of ["components/header", selected, "components/footer"]) {
|
|
22644
|
+
if (!template.files[file + ".liquid"]) continue;
|
|
22645
|
+
const result2 = await renderTemplatePage(template, file, context);
|
|
22646
|
+
if (!result2.ok) throw new ProjectError("Falha no Liquid da p\xE1gina.");
|
|
22647
|
+
html.push(result2.data.html);
|
|
22648
|
+
}
|
|
22649
|
+
const nonce = (0, import_node_crypto2.randomBytes)(24).toString("base64");
|
|
22650
|
+
const wrapperStyle = Object.entries(templateCssVars(template)).map(([key, value]) => `${key}:${value}`).join(";");
|
|
22651
|
+
const source = buildSandboxDocument({
|
|
22652
|
+
template,
|
|
22653
|
+
html: html.join(""),
|
|
22654
|
+
wrapperStyle,
|
|
22655
|
+
nonce,
|
|
22656
|
+
page: selected
|
|
22657
|
+
});
|
|
22658
|
+
const policy = `default-src 'none'; script-src 'nonce-${nonce}'; style-src 'unsafe-inline'; img-src https: data:; frame-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'`;
|
|
22659
|
+
return `<!doctype html><html lang="pt-BR"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="Content-Security-Policy" content="${escape3(policy)}"><title>CeuPay \u2014 pr\xE9via local</title></head><body>
|
|
22660
|
+
<nav aria-label="P\xE1ginas da pr\xE9via"><a href="/?page=index">In\xEDcio</a> \xB7 <a href="/?page=catalog">Cat\xE1logo</a> \xB7 <a href="/?page=product">Produto</a> \xB7 <a href="/?page=post">Post</a></nav>
|
|
22661
|
+
<p id="notice" role="status">Cat\xE1logo fict\xEDcio. Compras e navega\xE7\xE3o do template s\xE3o simuladas. Arquivos locais recarregam automaticamente.</p>
|
|
22662
|
+
<iframe title="Template da loja" sandbox="allow-scripts" referrerpolicy="no-referrer" style="width:100%;min-height:80vh;border:0" srcdoc="${escape3(source)}"></iframe>
|
|
22663
|
+
<script nonce="${nonce}">const frame=document.querySelector('iframe');window.addEventListener('message',e=>{if(e.source!==frame.contentWindow||e.origin!=='null'||!e.data||e.data.source!=='ceupay-template')return;if(e.data.type==='resize'&&Number.isFinite(e.data.height)){frame.style.height=Math.max(300,Math.min(30000,e.data.height))+'px';}else if(e.data.type==='navigate'||e.data.type==='addToCart'){document.getElementById('notice').textContent='Simula\xE7\xE3o: '+e.data.type;}});let version=${JSON.stringify(hash(template))};setInterval(async()=>{try{const next=await(await fetch('/version')).text();if(version!==undefined&&version!==next)location.reload();version=next;}catch{}},1000);</script></body></html>`;
|
|
22664
|
+
}
|
|
22665
|
+
async function serveProject(directory) {
|
|
22666
|
+
await privateRoot(directory);
|
|
22667
|
+
const server = import_node_http.default.createServer((request, response) => {
|
|
22668
|
+
void (async () => {
|
|
22669
|
+
const expected = `127.0.0.1:${server.address().port}`;
|
|
22670
|
+
if (request.method !== "GET" || request.headers.host !== expected || request.headers.origin && request.headers.origin !== `http://${expected}` || request.headers["sec-fetch-site"] && !["same-origin", "none"].includes(String(request.headers["sec-fetch-site"]))) {
|
|
22671
|
+
response.writeHead(403);
|
|
22672
|
+
response.end();
|
|
22673
|
+
return;
|
|
22674
|
+
}
|
|
22675
|
+
const url2 = new URL(request.url ?? "/", `http://${expected}`);
|
|
22676
|
+
response.setHeader("Cache-Control", "no-store");
|
|
22677
|
+
response.setHeader("X-Content-Type-Options", "nosniff");
|
|
22678
|
+
response.setHeader("Referrer-Policy", "no-referrer");
|
|
22679
|
+
response.setHeader("Content-Security-Policy", "frame-ancestors 'none'");
|
|
22680
|
+
if (url2.pathname === "/version") {
|
|
22681
|
+
const project = await loadProject(directory);
|
|
22682
|
+
response.setHeader("Content-Type", "text/plain");
|
|
22683
|
+
response.end(hash(project));
|
|
22684
|
+
} else if (url2.pathname === "/") {
|
|
22685
|
+
const document = await previewDocument(directory, url2.searchParams.get("page") ?? "index");
|
|
22686
|
+
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
22687
|
+
response.end(document);
|
|
22688
|
+
} else {
|
|
22689
|
+
response.writeHead(404);
|
|
22690
|
+
response.end();
|
|
22691
|
+
}
|
|
22692
|
+
})().catch(() => {
|
|
22693
|
+
if (!response.headersSent)
|
|
22694
|
+
response.writeHead(422, {
|
|
22695
|
+
"Content-Type": "text/plain; charset=utf-8"
|
|
22696
|
+
});
|
|
22697
|
+
response.end("Template inv\xE1lido. Corrija os arquivos e recarregue.");
|
|
22698
|
+
});
|
|
22699
|
+
});
|
|
22700
|
+
await new Promise((resolve, reject2) => {
|
|
22701
|
+
server.once("error", reject2);
|
|
22702
|
+
server.listen(0, "127.0.0.1", resolve);
|
|
22703
|
+
});
|
|
22704
|
+
const url = `http://127.0.0.1:${server.address().port}`;
|
|
22705
|
+
return {
|
|
22706
|
+
url,
|
|
22707
|
+
close: () => new Promise((resolve, reject2) => server.close((error) => error ? reject2(error) : resolve()))
|
|
22708
|
+
};
|
|
22709
|
+
}
|
|
22710
|
+
async function watchProject(directory, signal) {
|
|
22711
|
+
const root = await privateRoot(directory), operations = import_node_path3.default.join(root, ".ceupay-operations");
|
|
22712
|
+
await import_promises3.default.mkdir(operations, { mode: 448 }).catch((error) => {
|
|
22713
|
+
if (error.code !== "EEXIST") throw error;
|
|
22714
|
+
});
|
|
22715
|
+
await privateRoot(operations);
|
|
22716
|
+
for (const file of await import_promises3.default.readdir(operations)) {
|
|
22717
|
+
if (file.endsWith(".json")) {
|
|
22718
|
+
try {
|
|
22719
|
+
await import_promises3.default.lstat(import_node_path3.default.join(operations, file + ".confirmed"));
|
|
22720
|
+
} catch {
|
|
22721
|
+
throw new ProjectError(
|
|
22722
|
+
"H\xE1 opera\xE7\xE3o pendente. Preserve os arquivos, recupere com replay e baixe uma pasta nova antes de sincronizar."
|
|
22723
|
+
);
|
|
22724
|
+
}
|
|
22725
|
+
}
|
|
22726
|
+
}
|
|
22727
|
+
let observed = hash(await loadProject(root));
|
|
22728
|
+
let published = await remoteMatchesProject(root) ? observed : "";
|
|
22729
|
+
while (!signal.aborted) {
|
|
22730
|
+
await (0, import_promises4.setTimeout)(750, void 0, { signal }).catch(() => void 0);
|
|
22731
|
+
if (signal.aborted) break;
|
|
22732
|
+
let next;
|
|
22733
|
+
try {
|
|
22734
|
+
next = hash(await loadProject(root));
|
|
22735
|
+
} catch {
|
|
22736
|
+
continue;
|
|
22737
|
+
}
|
|
22738
|
+
if (next !== observed) {
|
|
22739
|
+
observed = next;
|
|
22740
|
+
continue;
|
|
22741
|
+
}
|
|
22742
|
+
if (next === published) continue;
|
|
22743
|
+
const file = import_node_path3.default.join(operations, (0, import_node_crypto2.randomUUID)() + ".json");
|
|
22744
|
+
await runRemote("prepare-publish", [root, file]);
|
|
22745
|
+
const updated = await runRemote("publish", [root, file, "--yes"]);
|
|
22746
|
+
if (updated !== true) throw new ProjectError("V\xEDnculo local n\xE3o avan\xE7ou. Preserve a opera\xE7\xE3o e baixe uma pasta nova.");
|
|
22747
|
+
await writeNew(file + ".confirmed", "confirmed\n");
|
|
22748
|
+
published = next;
|
|
22749
|
+
}
|
|
22750
|
+
}
|
|
22751
|
+
async function runLocal(command, args) {
|
|
22752
|
+
const [directory, ...flags] = args;
|
|
22753
|
+
if (!directory || flags.some((flag) => !["--watch", "--yes"].includes(flag)) || new Set(flags).size !== flags.length || flags.includes("--watch") !== flags.includes("--yes") || command === "serve" && flags.length)
|
|
22754
|
+
throw new ProjectError("Use start <pasta> [--watch --yes] ou serve <pasta>.");
|
|
22755
|
+
if (command === "start") {
|
|
22756
|
+
process.env.CEUPAY_EDITOR_TOKEN = await sessionSecret();
|
|
22757
|
+
try {
|
|
22758
|
+
await import_promises3.default.lstat(directory);
|
|
22759
|
+
} catch (error) {
|
|
22760
|
+
if (error.code !== "ENOENT") throw error;
|
|
22761
|
+
try {
|
|
22762
|
+
await runRemote("pull", [directory]);
|
|
22763
|
+
} catch (error2) {
|
|
22764
|
+
if (!(error2 instanceof ProjectError) || !error2.message.includes("n\xE3o tem template customizado")) throw error2;
|
|
22765
|
+
await runRemote("pull", [directory, "--base", "horizonte"]);
|
|
22766
|
+
}
|
|
22767
|
+
}
|
|
22768
|
+
}
|
|
22769
|
+
await loadProject(directory);
|
|
22770
|
+
const preview2 = await serveProject(directory);
|
|
22771
|
+
console.log(`Pr\xE9via interativa: ${preview2.url}
|
|
22772
|
+
Abra a pasta no Claude/Codex. Ctrl+C encerra.`);
|
|
22773
|
+
const controller = new AbortController();
|
|
22774
|
+
const stop = () => controller.abort();
|
|
22775
|
+
process.once("SIGINT", stop);
|
|
22776
|
+
process.once("SIGTERM", stop);
|
|
22777
|
+
try {
|
|
22778
|
+
if (flags.includes("--watch")) await watchProject(directory, controller.signal);
|
|
22779
|
+
else
|
|
22780
|
+
await new Promise(
|
|
22781
|
+
(resolve) => controller.signal.addEventListener("abort", () => resolve(), {
|
|
22782
|
+
once: true
|
|
22783
|
+
})
|
|
22784
|
+
);
|
|
22785
|
+
} finally {
|
|
22786
|
+
process.off("SIGINT", stop);
|
|
22787
|
+
process.off("SIGTERM", stop);
|
|
22788
|
+
await preview2.close();
|
|
22789
|
+
delete process.env.CEUPAY_EDITOR_TOKEN;
|
|
22790
|
+
}
|
|
22791
|
+
}
|
|
22251
22792
|
|
|
22252
22793
|
// src/main.ts
|
|
22253
22794
|
var HELP = `CeuPay templates \u2014 desenvolvimento local e piloto remoto
|
|
22254
22795
|
bases
|
|
22796
|
+
start <pasta> [--watch --yes]
|
|
22797
|
+
serve <pasta>
|
|
22255
22798
|
init <modelo> <nova-pasta>
|
|
22256
22799
|
import <exportacao.json> <nova-pasta>
|
|
22257
22800
|
validate <pasta>
|
|
@@ -22273,6 +22816,10 @@ async function main(args) {
|
|
|
22273
22816
|
const [major, minor] = process.versions.node.split(".").map(Number);
|
|
22274
22817
|
if (major < 22 || major === 22 && minor < 12) throw new ProjectError("Use Node 22.12 ou superior.");
|
|
22275
22818
|
const [command, first, second] = args;
|
|
22819
|
+
if (command === "start" || command === "serve") {
|
|
22820
|
+
await runLocal(command, args.slice(1));
|
|
22821
|
+
return;
|
|
22822
|
+
}
|
|
22276
22823
|
if (!args.length || args.length === 1 && ["help", "--help"].includes(command)) {
|
|
22277
22824
|
console.log(HELP);
|
|
22278
22825
|
return;
|
|
@@ -22291,7 +22838,8 @@ async function main(args) {
|
|
|
22291
22838
|
return;
|
|
22292
22839
|
}
|
|
22293
22840
|
if (command === "preview") {
|
|
22294
|
-
if (args.length !== 3 && !(args.length === 5 && args[3] === "--page"))
|
|
22841
|
+
if (args.length !== 3 && !(args.length === 5 && args[3] === "--page"))
|
|
22842
|
+
throw new ProjectError("Argumentos inv\xE1lidos. Consulte help.");
|
|
22295
22843
|
await preview(first, second, args.length === 5 ? `pages/${args[4]}` : "pages/index");
|
|
22296
22844
|
console.log("Pr\xE9via local criada.");
|
|
22297
22845
|
return;
|