@valbuild/shared 0.150.12 → 0.150.16
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 +31 -0
- package/client/dist/valbuild-shared-client.cjs.dev.js +2 -1
- package/client/dist/valbuild-shared-client.cjs.prod.js +2 -1
- package/client/dist/valbuild-shared-client.esm.js +1 -1
- package/dist/declarations/src/client/index.d.ts +1 -0
- package/dist/declarations/src/internal/ApiRoutes.d.ts +375 -94
- package/dist/declarations/src/internal/aiTools/toolNames.d.ts +1 -1
- package/dist/declarations/src/internal/index.d.ts +3 -0
- package/dist/declarations/src/internal/localeAt.d.ts +86 -1
- package/dist/declarations/src/internal/localeRelocation.d.ts +46 -0
- package/dist/declarations/src/internal/pageScreenshot.d.ts +40 -0
- package/dist/declarations/src/internal/server/types.d.ts +3 -3
- package/dist/declarations/src/internal/sketchpad/sketchFormat.d.ts +118 -0
- package/dist/declarations/src/internal/valCanvasProtocol.d.ts +21 -0
- package/dist/declarations/src/internal/zod/History.d.ts +7 -7
- package/dist/declarations/src/internal/zod/Patch.d.ts +1 -0
- package/dist/declarations/src/internal/zod/SerializedSchema.d.ts +20 -2
- package/dist/{getSitemapTree-97b3166f.esm.js → getSitemapTree-7c848c94.esm.js} +137 -2
- package/dist/{getSitemapTree-5354ce90.cjs.prod.js → getSitemapTree-97713490.cjs.prod.js} +155 -1
- package/dist/{getSitemapTree-d934ff9c.cjs.dev.js → getSitemapTree-98642b57.cjs.dev.js} +155 -1
- package/internal/dist/valbuild-shared-internal.cjs.dev.js +837 -15
- package/internal/dist/valbuild-shared-internal.cjs.prod.js +837 -15
- package/internal/dist/valbuild-shared-internal.esm.js +821 -17
- package/package.json +2 -1
|
@@ -7,7 +7,7 @@ var core = require('@valbuild/core');
|
|
|
7
7
|
var zod = require('zod');
|
|
8
8
|
var protocol = require('../../dist/protocol-d0efb8cd.cjs.dev.js');
|
|
9
9
|
var zodValidationError = require('zod-validation-error');
|
|
10
|
-
var getSitemapTree = require('../../dist/getSitemapTree-
|
|
10
|
+
var getSitemapTree = require('../../dist/getSitemapTree-98642b57.cjs.dev.js');
|
|
11
11
|
var FlexSearch = require('flexsearch');
|
|
12
12
|
var wrapNativeSuper = require('../../dist/wrapNativeSuper-933f991e.cjs.dev.js');
|
|
13
13
|
var utils = require('../../dist/utils-d3d8b4b5.cjs.dev.js');
|
|
@@ -1670,6 +1670,40 @@ var AnalyticsBeacon = zod.z.object({
|
|
|
1670
1670
|
}, {
|
|
1671
1671
|
message: "At most ".concat(MAX_ANALYTICS_PATHS_PER_BEACON, " paths a beacon")
|
|
1672
1672
|
});
|
|
1673
|
+
/**
|
|
1674
|
+
* A Sketchpad, as the server keeps it: a rough page written in the strict
|
|
1675
|
+
* format of `sketchpad/sketchFormat.ts`, owned by the project and nothing
|
|
1676
|
+
* else. Not by an AI session -- the assistant that made it remembers its id,
|
|
1677
|
+
* and any chat can read it again -- and not by a page: `page` is a label for
|
|
1678
|
+
* which page it is about, and can be changed or cleared.
|
|
1679
|
+
*
|
|
1680
|
+
* `version` goes up by one on every change, and a change names the version
|
|
1681
|
+
* it was made against, so two writers cannot overwrite each other unseen.
|
|
1682
|
+
*/
|
|
1683
|
+
var Sketchpad = zod.z.object({
|
|
1684
|
+
id: zod.z.string(),
|
|
1685
|
+
page: zod.z.string().nullable(),
|
|
1686
|
+
/** Its first heading, for a list to name it by. */
|
|
1687
|
+
title: zod.z.string().nullable(),
|
|
1688
|
+
text: zod.z.string(),
|
|
1689
|
+
version: zod.z.number()["int"](),
|
|
1690
|
+
archived: zod.z["boolean"](),
|
|
1691
|
+
createdAt: zod.z.string(),
|
|
1692
|
+
updatedAt: zod.z.string(),
|
|
1693
|
+
/** Profile ids; null where nobody was signed in (local dev, the demo). */
|
|
1694
|
+
createdBy: zod.z.string().nullable(),
|
|
1695
|
+
updatedBy: zod.z.string().nullable()
|
|
1696
|
+
});
|
|
1697
|
+
var SketchpadSummary = Sketchpad.omit({
|
|
1698
|
+
text: true
|
|
1699
|
+
});
|
|
1700
|
+
/** A line of a sketch the server would not take, and why. */
|
|
1701
|
+
var SketchErrorZ = zod.z.object({
|
|
1702
|
+
line: zod.z.number(),
|
|
1703
|
+
message: zod.z.string()
|
|
1704
|
+
});
|
|
1705
|
+
/** The most text a sketchpad holds, in UTF-8 bytes: a page, not a site. */
|
|
1706
|
+
var SKETCHPAD_MAX_TEXT_LENGTH = 256 * 1024;
|
|
1673
1707
|
var Api = {
|
|
1674
1708
|
"/draft/enable": {
|
|
1675
1709
|
GET: {
|
|
@@ -2401,6 +2435,124 @@ var Api = {
|
|
|
2401
2435
|
})
|
|
2402
2436
|
}
|
|
2403
2437
|
},
|
|
2438
|
+
/**
|
|
2439
|
+
* The project's sketchpads: list them, or make one. See `Sketchpad`.
|
|
2440
|
+
* Making one answers with its id, which is what an assistant keeps to
|
|
2441
|
+
* read and change it later.
|
|
2442
|
+
*/
|
|
2443
|
+
"/sketchpads": {
|
|
2444
|
+
GET: {
|
|
2445
|
+
req: {
|
|
2446
|
+
query: {
|
|
2447
|
+
/** `exclude` (the default), `include`, or `only`. */
|
|
2448
|
+
archived: onlyOneStringQueryParam.optional(),
|
|
2449
|
+
/** Only those about this page. */
|
|
2450
|
+
page: onlyOneStringQueryParam.optional()
|
|
2451
|
+
},
|
|
2452
|
+
cookies: {
|
|
2453
|
+
val_session: zod.z.string().optional()
|
|
2454
|
+
}
|
|
2455
|
+
},
|
|
2456
|
+
res: zod.z.union([unauthorizedResponse, zod.z.object({
|
|
2457
|
+
status: zod.z.literal(400),
|
|
2458
|
+
json: GenericError
|
|
2459
|
+
}), zod.z.object({
|
|
2460
|
+
status: zod.z.literal(500),
|
|
2461
|
+
json: GenericError
|
|
2462
|
+
}), zod.z.object({
|
|
2463
|
+
status: zod.z.literal(200),
|
|
2464
|
+
json: zod.z.object({
|
|
2465
|
+
sketchpads: zod.z.array(SketchpadSummary)
|
|
2466
|
+
})
|
|
2467
|
+
})])
|
|
2468
|
+
},
|
|
2469
|
+
POST: {
|
|
2470
|
+
req: {
|
|
2471
|
+
body: zod.z.object({
|
|
2472
|
+
text: zod.z.string(),
|
|
2473
|
+
page: zod.z.string().nullable()
|
|
2474
|
+
}),
|
|
2475
|
+
cookies: {
|
|
2476
|
+
val_session: zod.z.string().optional()
|
|
2477
|
+
}
|
|
2478
|
+
},
|
|
2479
|
+
res: zod.z.union([unauthorizedResponse, zod.z.object({
|
|
2480
|
+
status: zod.z.literal(400),
|
|
2481
|
+
json: zod.z.object({
|
|
2482
|
+
message: zod.z.string(),
|
|
2483
|
+
/** Lines of the text that are not in the sketch format. */
|
|
2484
|
+
errors: zod.z.array(SketchErrorZ).optional()
|
|
2485
|
+
})
|
|
2486
|
+
}), zod.z.object({
|
|
2487
|
+
status: zod.z.literal(500),
|
|
2488
|
+
json: GenericError
|
|
2489
|
+
}), zod.z.object({
|
|
2490
|
+
status: zod.z.literal(201),
|
|
2491
|
+
json: zod.z.object({
|
|
2492
|
+
sketchpad: Sketchpad
|
|
2493
|
+
})
|
|
2494
|
+
})])
|
|
2495
|
+
}
|
|
2496
|
+
},
|
|
2497
|
+
/** One sketchpad: read it, or change its text, its page or whether it is archived. */
|
|
2498
|
+
"/sketchpad": {
|
|
2499
|
+
GET: {
|
|
2500
|
+
req: {
|
|
2501
|
+
query: {
|
|
2502
|
+
id: onlyOneStringQueryParam
|
|
2503
|
+
},
|
|
2504
|
+
cookies: {
|
|
2505
|
+
val_session: zod.z.string().optional()
|
|
2506
|
+
}
|
|
2507
|
+
},
|
|
2508
|
+
res: zod.z.union([unauthorizedResponse, notFoundResponse, zod.z.object({
|
|
2509
|
+
status: zod.z.literal(500),
|
|
2510
|
+
json: GenericError
|
|
2511
|
+
}), zod.z.object({
|
|
2512
|
+
status: zod.z.literal(200),
|
|
2513
|
+
json: zod.z.object({
|
|
2514
|
+
sketchpad: Sketchpad
|
|
2515
|
+
})
|
|
2516
|
+
})])
|
|
2517
|
+
},
|
|
2518
|
+
PATCH: {
|
|
2519
|
+
req: {
|
|
2520
|
+
body: zod.z.object({
|
|
2521
|
+
id: zod.z.string(),
|
|
2522
|
+
/** The version this change was made against. */
|
|
2523
|
+
baseVersion: zod.z.number()["int"](),
|
|
2524
|
+
text: zod.z.string().optional(),
|
|
2525
|
+
page: zod.z.string().nullable().optional(),
|
|
2526
|
+
archived: zod.z["boolean"]().optional()
|
|
2527
|
+
}),
|
|
2528
|
+
cookies: {
|
|
2529
|
+
val_session: zod.z.string().optional()
|
|
2530
|
+
}
|
|
2531
|
+
},
|
|
2532
|
+
res: zod.z.union([unauthorizedResponse, notFoundResponse, zod.z.object({
|
|
2533
|
+
status: zod.z.literal(400),
|
|
2534
|
+
json: zod.z.object({
|
|
2535
|
+
message: zod.z.string(),
|
|
2536
|
+
errors: zod.z.array(SketchErrorZ).optional()
|
|
2537
|
+
})
|
|
2538
|
+
}), /** Changed since `baseVersion`: here is how it is now. */
|
|
2539
|
+
zod.z.object({
|
|
2540
|
+
status: zod.z.literal(409),
|
|
2541
|
+
json: zod.z.object({
|
|
2542
|
+
message: zod.z.string(),
|
|
2543
|
+
sketchpad: Sketchpad
|
|
2544
|
+
})
|
|
2545
|
+
}), zod.z.object({
|
|
2546
|
+
status: zod.z.literal(500),
|
|
2547
|
+
json: GenericError
|
|
2548
|
+
}), zod.z.object({
|
|
2549
|
+
status: zod.z.literal(200),
|
|
2550
|
+
json: zod.z.object({
|
|
2551
|
+
sketchpad: Sketchpad
|
|
2552
|
+
})
|
|
2553
|
+
})])
|
|
2554
|
+
}
|
|
2555
|
+
},
|
|
2404
2556
|
"/upload/patches": {
|
|
2405
2557
|
POST: {
|
|
2406
2558
|
req: {
|
|
@@ -5370,6 +5522,7 @@ function resolveSchemaSourceFixes(validationErrors, snapshot) {
|
|
|
5370
5522
|
* in most projects, and for every project that has not declared any languages.
|
|
5371
5523
|
*/
|
|
5372
5524
|
function localeAt(path, snapshot) {
|
|
5525
|
+
var _localeScopeAt$locale, _localeScopeAt;
|
|
5373
5526
|
var available = declaredLocales(snapshot);
|
|
5374
5527
|
if (available.length === 0) {
|
|
5375
5528
|
// Nothing can be one of no languages. Answering `null` rather than reading
|
|
@@ -5378,18 +5531,66 @@ function localeAt(path, snapshot) {
|
|
|
5378
5531
|
return null;
|
|
5379
5532
|
}
|
|
5380
5533
|
var _Internal$splitModule = core.Internal.splitModuleFilePathAndModulePath(path),
|
|
5381
|
-
_Internal$splitModule2 = createForOfIteratorHelper._slicedToArray(_Internal$splitModule,
|
|
5382
|
-
moduleFilePath = _Internal$splitModule2[0]
|
|
5383
|
-
modulePath = _Internal$splitModule2[1];
|
|
5534
|
+
_Internal$splitModule2 = createForOfIteratorHelper._slicedToArray(_Internal$splitModule, 1),
|
|
5535
|
+
moduleFilePath = _Internal$splitModule2[0];
|
|
5384
5536
|
var schema = snapshot.schemas[moduleFilePath];
|
|
5385
5537
|
var source = snapshot.sources[moduleFilePath];
|
|
5386
5538
|
if (schema === undefined || source === undefined) {
|
|
5387
5539
|
return null;
|
|
5388
5540
|
}
|
|
5541
|
+
return (_localeScopeAt$locale = (_localeScopeAt = localeScopeAt(path, schema, source, available)) === null || _localeScopeAt === void 0 ? void 0 : _localeScopeAt.locale) !== null && _localeScopeAt$locale !== void 0 ? _localeScopeAt$locale : null;
|
|
5542
|
+
}
|
|
5543
|
+
|
|
5544
|
+
/**
|
|
5545
|
+
* Where the scope governing a path opens, and how.
|
|
5546
|
+
*
|
|
5547
|
+
* - `field`: the node `depth` segments down has a locale field. `depth` 0 is the
|
|
5548
|
+
* module root.
|
|
5549
|
+
* - `record-key`: segment `depth` is a key of a locale-keyed record, which sits
|
|
5550
|
+
* `depth` segments down.
|
|
5551
|
+
* - `route-key`: segment `depth` is a route whose parameters name the language,
|
|
5552
|
+
* in the router `depth` segments down (in practice the module root).
|
|
5553
|
+
*
|
|
5554
|
+
* The opener is what decides where an editor goes when the Studio's language
|
|
5555
|
+
* changes under them — the same entry in another language for a key, the
|
|
5556
|
+
* parent for a field. See `relocateForLocale`.
|
|
5557
|
+
*/
|
|
5558
|
+
|
|
5559
|
+
/**
|
|
5560
|
+
* The scope that governs a path, read from that module's schema and source
|
|
5561
|
+
* alone, or `null` where none does.
|
|
5562
|
+
*
|
|
5563
|
+
* {@link localeAt} for a caller that already has the module in hand — the
|
|
5564
|
+
* Studio, which has the project's languages from its own provider and would
|
|
5565
|
+
* otherwise have to assemble a snapshot of every module to ask about one.
|
|
5566
|
+
*/
|
|
5567
|
+
function localeScopeAt(path, schema, source, available) {
|
|
5568
|
+
if (available.length === 0) {
|
|
5569
|
+
return null;
|
|
5570
|
+
}
|
|
5571
|
+
var _Internal$splitModule3 = core.Internal.splitModuleFilePathAndModulePath(path),
|
|
5572
|
+
_Internal$splitModule4 = createForOfIteratorHelper._slicedToArray(_Internal$splitModule3, 2),
|
|
5573
|
+
moduleFilePath = _Internal$splitModule4[0],
|
|
5574
|
+
modulePath = _Internal$splitModule4[1];
|
|
5389
5575
|
var segments = modulePath ? core.Internal.splitModulePath(modulePath) : [];
|
|
5390
5576
|
return walk(schema, source, segments, available, moduleFilePath);
|
|
5391
5577
|
}
|
|
5392
5578
|
|
|
5579
|
+
/**
|
|
5580
|
+
* The language a whole module is in: the one its root's locale field names, or
|
|
5581
|
+
* `null` where its root has none.
|
|
5582
|
+
*
|
|
5583
|
+
* The only way a module is in one language as a whole — a locale-keyed record
|
|
5584
|
+
* or a router at the root is every one of its languages at once. Needs no path,
|
|
5585
|
+
* so a list of modules can ask it of each.
|
|
5586
|
+
*/
|
|
5587
|
+
function localeOfModuleRoot(schema, source, available) {
|
|
5588
|
+
if (available.length === 0) {
|
|
5589
|
+
return null;
|
|
5590
|
+
}
|
|
5591
|
+
return enter(schema, source, available).locale;
|
|
5592
|
+
}
|
|
5593
|
+
|
|
5393
5594
|
/**
|
|
5394
5595
|
* The language a locale schema's value MEANS, or `null` if it means none of
|
|
5395
5596
|
* the project's.
|
|
@@ -5435,11 +5636,32 @@ function isLocaleSchema(schema) {
|
|
|
5435
5636
|
return schema.type === "locale" || schema.type === "enum" && schema.locales !== undefined;
|
|
5436
5637
|
}
|
|
5437
5638
|
|
|
5639
|
+
/**
|
|
5640
|
+
* Whether a router's URLs name the language each page is in — one of its route
|
|
5641
|
+
* parameters is a locale (`s.router(router, { locale: … }, item)`).
|
|
5642
|
+
*/
|
|
5643
|
+
function hasLocaleRouteParam(schema) {
|
|
5644
|
+
return schema.type === "record" && schema.params !== undefined && Object.values(schema.params).some(isLocaleSchema);
|
|
5645
|
+
}
|
|
5646
|
+
|
|
5438
5647
|
/**
|
|
5439
5648
|
* The language a router's key is in, where one of its route parameters is a
|
|
5440
5649
|
* locale — `/nb/blog/hei` is `nb-NO` when `locale` maps `nb` to it.
|
|
5650
|
+
*
|
|
5651
|
+
* Answered from the key alone, with no content read: which is what lets the
|
|
5652
|
+
* Studio's page tree filter every page of a site without loading one of them.
|
|
5441
5653
|
*/
|
|
5442
5654
|
function localeOfRouteKey(schema, moduleFilePath, key, available) {
|
|
5655
|
+
var param = localeParamOfRouteKey(schema, moduleFilePath, key);
|
|
5656
|
+
return param === null ? null : localeMeantBy(param.schema, param.value, available);
|
|
5657
|
+
}
|
|
5658
|
+
|
|
5659
|
+
/**
|
|
5660
|
+
* The route parameters a key gives its router, and which of them is the
|
|
5661
|
+
* language — or `null` where the router has no locale parameter or the key is
|
|
5662
|
+
* not one of its URLs.
|
|
5663
|
+
*/
|
|
5664
|
+
function localeParamOfRouteKey(schema, moduleFilePath, key) {
|
|
5443
5665
|
if (schema.params === undefined || schema.router === undefined) {
|
|
5444
5666
|
return null;
|
|
5445
5667
|
}
|
|
@@ -5456,7 +5678,12 @@ function localeOfRouteKey(schema, moduleFilePath, key, available) {
|
|
|
5456
5678
|
name = _Object$entries$_i[0],
|
|
5457
5679
|
param = _Object$entries$_i[1];
|
|
5458
5680
|
if (isLocaleSchema(param) && Object.prototype.hasOwnProperty.call(values, name)) {
|
|
5459
|
-
return
|
|
5681
|
+
return {
|
|
5682
|
+
name: name,
|
|
5683
|
+
schema: param,
|
|
5684
|
+
value: values[name],
|
|
5685
|
+
values: values
|
|
5686
|
+
};
|
|
5460
5687
|
}
|
|
5461
5688
|
}
|
|
5462
5689
|
return null;
|
|
@@ -5476,16 +5703,22 @@ function localeOfRouteKey(schema, moduleFilePath, key, available) {
|
|
|
5476
5703
|
*/
|
|
5477
5704
|
function walk(schema, source, segments, available, moduleFilePath) {
|
|
5478
5705
|
var entered = enter(schema, source, available);
|
|
5479
|
-
var
|
|
5706
|
+
var scope = entered.locale === null ? null : {
|
|
5707
|
+
kind: "field",
|
|
5708
|
+
locale: entered.locale,
|
|
5709
|
+
depth: 0
|
|
5710
|
+
};
|
|
5480
5711
|
var currentSchema = entered.schema;
|
|
5481
5712
|
var currentSource = source;
|
|
5482
|
-
var _iterator = createForOfIteratorHelper._createForOfIteratorHelper(segments),
|
|
5713
|
+
var _iterator = createForOfIteratorHelper._createForOfIteratorHelper(segments.entries()),
|
|
5483
5714
|
_step;
|
|
5484
5715
|
try {
|
|
5485
5716
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
5486
|
-
var
|
|
5717
|
+
var _step$value = createForOfIteratorHelper._slicedToArray(_step.value, 2),
|
|
5718
|
+
index = _step$value[0],
|
|
5719
|
+
segment = _step$value[1];
|
|
5487
5720
|
if (currentSchema === undefined) {
|
|
5488
|
-
return
|
|
5721
|
+
return scope;
|
|
5489
5722
|
}
|
|
5490
5723
|
if (currentSchema.type === "record") {
|
|
5491
5724
|
if (currentSchema.key !== undefined && isLocaleSchema(currentSchema.key)) {
|
|
@@ -5494,14 +5727,24 @@ function walk(schema, source, segments, available, moduleFilePath) {
|
|
|
5494
5727
|
// the tag it stands for when the key is an enum with `.locales()`.
|
|
5495
5728
|
var resolved = localeMeantBy(currentSchema.key, segment, available);
|
|
5496
5729
|
if (resolved !== null) {
|
|
5497
|
-
|
|
5730
|
+
scope = {
|
|
5731
|
+
kind: "record-key",
|
|
5732
|
+
locale: resolved,
|
|
5733
|
+
depth: index,
|
|
5734
|
+
keySchema: currentSchema.key
|
|
5735
|
+
};
|
|
5498
5736
|
}
|
|
5499
5737
|
} else if (currentSchema.params !== undefined) {
|
|
5500
5738
|
// A router whose URL names the language: the key is a URL, and one of
|
|
5501
5739
|
// its parameters is the answer.
|
|
5502
5740
|
var _resolved = localeOfRouteKey(currentSchema, moduleFilePath, segment, available);
|
|
5503
5741
|
if (_resolved !== null) {
|
|
5504
|
-
|
|
5742
|
+
scope = {
|
|
5743
|
+
kind: "route-key",
|
|
5744
|
+
locale: _resolved,
|
|
5745
|
+
depth: index,
|
|
5746
|
+
router: currentSchema
|
|
5747
|
+
};
|
|
5505
5748
|
}
|
|
5506
5749
|
}
|
|
5507
5750
|
currentSchema = currentSchema.item;
|
|
@@ -5511,13 +5754,17 @@ function walk(schema, source, segments, available, moduleFilePath) {
|
|
|
5511
5754
|
currentSchema = currentSchema.items[segment];
|
|
5512
5755
|
} else {
|
|
5513
5756
|
// A leaf, or richtext's internal structure. Nothing below opens a scope.
|
|
5514
|
-
return
|
|
5757
|
+
return scope;
|
|
5515
5758
|
}
|
|
5516
5759
|
currentSource = childSource(currentSource, segment);
|
|
5517
5760
|
entered = enter(currentSchema, currentSource, available);
|
|
5518
5761
|
currentSchema = entered.schema;
|
|
5519
5762
|
if (entered.locale !== null) {
|
|
5520
|
-
|
|
5763
|
+
scope = {
|
|
5764
|
+
kind: "field",
|
|
5765
|
+
locale: entered.locale,
|
|
5766
|
+
depth: index + 1
|
|
5767
|
+
};
|
|
5521
5768
|
}
|
|
5522
5769
|
}
|
|
5523
5770
|
} catch (err) {
|
|
@@ -5525,7 +5772,7 @@ function walk(schema, source, segments, available, moduleFilePath) {
|
|
|
5525
5772
|
} finally {
|
|
5526
5773
|
_iterator.f();
|
|
5527
5774
|
}
|
|
5528
|
-
return
|
|
5775
|
+
return scope;
|
|
5529
5776
|
}
|
|
5530
5777
|
|
|
5531
5778
|
/**
|
|
@@ -5615,6 +5862,187 @@ function isJsonObject(source) {
|
|
|
5615
5862
|
return createForOfIteratorHelper._typeof(source) === "object" && source !== null && !Array.isArray(source);
|
|
5616
5863
|
}
|
|
5617
5864
|
|
|
5865
|
+
/**
|
|
5866
|
+
* Where an editor goes when the Studio's language changes under them.
|
|
5867
|
+
*
|
|
5868
|
+
* - `stay`: the path is in that language, or in none.
|
|
5869
|
+
* - `path`: the same entry in that language (`counterpart`), or the nearest
|
|
5870
|
+
* parent that is not in another language (`parent`).
|
|
5871
|
+
* - `home`: neither exists, so the editor goes to the Studio's start, with
|
|
5872
|
+
* nothing selected.
|
|
5873
|
+
*/
|
|
5874
|
+
|
|
5875
|
+
/**
|
|
5876
|
+
* Where to move a path to when the Studio is switched to `locale`.
|
|
5877
|
+
*
|
|
5878
|
+
* The rule, in the order it is tried:
|
|
5879
|
+
*
|
|
5880
|
+
* 1. **The same entry in `locale`, where Val KNOWS it.** That is two cases:
|
|
5881
|
+
* a locale-keyed record, where the counterpart of `"en-US"` is the
|
|
5882
|
+
* `"nb-NO"` key of the same record; and a router whose URLs name their
|
|
5883
|
+
* language, where `/about` and `/nb/about` differ only in it. Only a key
|
|
5884
|
+
* that exists is taken, and the rest of the path is kept as far as it
|
|
5885
|
+
* still exists, so an editor on a field lands on that field.
|
|
5886
|
+
* 2. **Otherwise the nearest parent that is not in another language.** An
|
|
5887
|
+
* English post in a list of posts gives the list, now showing Norwegian.
|
|
5888
|
+
* 3. **Otherwise the Studio's start**, which is `home`: nothing selected. That
|
|
5889
|
+
* is where an object at the module root opened the scope (the whole module
|
|
5890
|
+
* is in another language), and where the parent would be a router: a list
|
|
5891
|
+
* of pages is not a page, and the Pages tree is how an editor sees one.
|
|
5892
|
+
*
|
|
5893
|
+
* Not the site's root page, and not any other page: which language a page is
|
|
5894
|
+
* in is the page's own business, and `/` can be in the language the editor
|
|
5895
|
+
* just left. The start screen is in no language.
|
|
5896
|
+
*
|
|
5897
|
+
* Never a guess. Two pages whose URLs differ in more than the language — a
|
|
5898
|
+
* Norwegian slug for a Norwegian page — are not known to be translations of
|
|
5899
|
+
* each other, so that is `home` rather than whichever page looks closest.
|
|
5900
|
+
*/
|
|
5901
|
+
function relocateForLocale(path, locale, schema, source, available) {
|
|
5902
|
+
var scope = localeScopeAt(path, schema, source, available);
|
|
5903
|
+
if (scope === null || scope.locale === locale) {
|
|
5904
|
+
return {
|
|
5905
|
+
type: "stay"
|
|
5906
|
+
};
|
|
5907
|
+
}
|
|
5908
|
+
var _Internal$splitModule = core.Internal.splitModuleFilePathAndModulePath(path),
|
|
5909
|
+
_Internal$splitModule2 = createForOfIteratorHelper._slicedToArray(_Internal$splitModule, 2),
|
|
5910
|
+
moduleFilePath = _Internal$splitModule2[0],
|
|
5911
|
+
modulePath = _Internal$splitModule2[1];
|
|
5912
|
+
var segments = modulePath ? core.Internal.splitModulePath(modulePath) : [];
|
|
5913
|
+
var at = function at(parts) {
|
|
5914
|
+
return core.Internal.joinModuleFilePathAndModulePath(moduleFilePath, core.Internal.patchPathToModulePath(parts));
|
|
5915
|
+
};
|
|
5916
|
+
var prefix = segments.slice(0, scope.depth);
|
|
5917
|
+
var rest = segments.slice(scope.depth + 1);
|
|
5918
|
+
if (scope.kind === "record-key") {
|
|
5919
|
+
var record = sourceAt(source, prefix);
|
|
5920
|
+
var key = isJsonObject(record) ? Object.keys(record).find(function (candidate) {
|
|
5921
|
+
return localeMeantBy(scope.keySchema, candidate, available) === locale;
|
|
5922
|
+
}) : undefined;
|
|
5923
|
+
if (key !== undefined) {
|
|
5924
|
+
return {
|
|
5925
|
+
type: "path",
|
|
5926
|
+
path: at(existingPart(source, [].concat(createForOfIteratorHelper._toConsumableArray(prefix), [key]), rest)),
|
|
5927
|
+
reason: "counterpart"
|
|
5928
|
+
};
|
|
5929
|
+
}
|
|
5930
|
+
return {
|
|
5931
|
+
type: "path",
|
|
5932
|
+
path: at(prefix),
|
|
5933
|
+
reason: "parent"
|
|
5934
|
+
};
|
|
5935
|
+
}
|
|
5936
|
+
if (scope.kind === "route-key") {
|
|
5937
|
+
var router = sourceAt(source, prefix);
|
|
5938
|
+
var current = localeParamOfRouteKey(scope.router, moduleFilePath, segments[scope.depth]);
|
|
5939
|
+
if (isJsonObject(router) && current !== null) {
|
|
5940
|
+
var _key = Object.keys(router).find(function (candidate) {
|
|
5941
|
+
var other = localeParamOfRouteKey(scope.router, moduleFilePath, candidate);
|
|
5942
|
+
return other !== null && localeMeantBy(other.schema, other.value, available) === locale && sameRouteExcept(current.values, other.values, current.name);
|
|
5943
|
+
});
|
|
5944
|
+
if (_key !== undefined) {
|
|
5945
|
+
return {
|
|
5946
|
+
type: "path",
|
|
5947
|
+
path: at(existingPart(source, [].concat(createForOfIteratorHelper._toConsumableArray(prefix), [_key]), rest)),
|
|
5948
|
+
reason: "counterpart"
|
|
5949
|
+
};
|
|
5950
|
+
}
|
|
5951
|
+
}
|
|
5952
|
+
return {
|
|
5953
|
+
type: "home"
|
|
5954
|
+
};
|
|
5955
|
+
}
|
|
5956
|
+
|
|
5957
|
+
// A locale FIELD opened the scope, on the node `depth` segments down.
|
|
5958
|
+
if (scope.depth === 0) {
|
|
5959
|
+
return {
|
|
5960
|
+
type: "home"
|
|
5961
|
+
};
|
|
5962
|
+
}
|
|
5963
|
+
var parent = segments.slice(0, scope.depth - 1);
|
|
5964
|
+
if (parent.length === 0 && schema.type === "record" && schema.router !== undefined) {
|
|
5965
|
+
return {
|
|
5966
|
+
type: "home"
|
|
5967
|
+
};
|
|
5968
|
+
}
|
|
5969
|
+
return {
|
|
5970
|
+
type: "path",
|
|
5971
|
+
path: at(parent),
|
|
5972
|
+
reason: "parent"
|
|
5973
|
+
};
|
|
5974
|
+
}
|
|
5975
|
+
|
|
5976
|
+
/** The source at `parts` below `source`, or `null` where it runs out. */
|
|
5977
|
+
function sourceAt(source, parts) {
|
|
5978
|
+
var current = source;
|
|
5979
|
+
var _iterator = createForOfIteratorHelper._createForOfIteratorHelper(parts),
|
|
5980
|
+
_step;
|
|
5981
|
+
try {
|
|
5982
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
5983
|
+
var part = _step.value;
|
|
5984
|
+
current = childSource(current, part);
|
|
5985
|
+
}
|
|
5986
|
+
} catch (err) {
|
|
5987
|
+
_iterator.e(err);
|
|
5988
|
+
} finally {
|
|
5989
|
+
_iterator.f();
|
|
5990
|
+
}
|
|
5991
|
+
return current;
|
|
5992
|
+
}
|
|
5993
|
+
|
|
5994
|
+
/**
|
|
5995
|
+
* `base`, followed by as much of `rest` as the source still has.
|
|
5996
|
+
*
|
|
5997
|
+
* The counterpart of a field is the same field in the other language's entry,
|
|
5998
|
+
* but that entry can be `null` — declared and not yet written — or shorter (a
|
|
5999
|
+
* list with fewer items). Landing on the entry then is the right answer: it is
|
|
6000
|
+
* the translation the editor is about to write.
|
|
6001
|
+
*/
|
|
6002
|
+
function existingPart(source, base, rest) {
|
|
6003
|
+
var parts = createForOfIteratorHelper._toConsumableArray(base);
|
|
6004
|
+
var current = sourceAt(source, base);
|
|
6005
|
+
var _iterator2 = createForOfIteratorHelper._createForOfIteratorHelper(rest),
|
|
6006
|
+
_step2;
|
|
6007
|
+
try {
|
|
6008
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
6009
|
+
var part = _step2.value;
|
|
6010
|
+
var next = childSource(current, part);
|
|
6011
|
+
if (next === null) {
|
|
6012
|
+
break;
|
|
6013
|
+
}
|
|
6014
|
+
parts.push(part);
|
|
6015
|
+
current = next;
|
|
6016
|
+
}
|
|
6017
|
+
} catch (err) {
|
|
6018
|
+
_iterator2.e(err);
|
|
6019
|
+
} finally {
|
|
6020
|
+
_iterator2.f();
|
|
6021
|
+
}
|
|
6022
|
+
return parts;
|
|
6023
|
+
}
|
|
6024
|
+
|
|
6025
|
+
/** Whether two routes' parameters agree on everything but `ignore`. */
|
|
6026
|
+
function sameRouteExcept(a, b, ignore) {
|
|
6027
|
+
var names = new Set([].concat(createForOfIteratorHelper._toConsumableArray(Object.keys(a)), createForOfIteratorHelper._toConsumableArray(Object.keys(b))));
|
|
6028
|
+
var _iterator3 = createForOfIteratorHelper._createForOfIteratorHelper(names),
|
|
6029
|
+
_step3;
|
|
6030
|
+
try {
|
|
6031
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
6032
|
+
var _a$name, _b$name;
|
|
6033
|
+
var name = _step3.value;
|
|
6034
|
+
if (name !== ignore && ((_a$name = a[name]) !== null && _a$name !== void 0 ? _a$name : null) !== ((_b$name = b[name]) !== null && _b$name !== void 0 ? _b$name : null)) {
|
|
6035
|
+
return false;
|
|
6036
|
+
}
|
|
6037
|
+
}
|
|
6038
|
+
} catch (err) {
|
|
6039
|
+
_iterator3.e(err);
|
|
6040
|
+
} finally {
|
|
6041
|
+
_iterator3.f();
|
|
6042
|
+
}
|
|
6043
|
+
return true;
|
|
6044
|
+
}
|
|
6045
|
+
|
|
5618
6046
|
/**
|
|
5619
6047
|
* Local `yyyy-MM-dd`, which is the one thing this module used `date-fns` for.
|
|
5620
6048
|
*
|
|
@@ -5792,7 +6220,383 @@ function emptyRecord(schema, context) {
|
|
|
5792
6220
|
}));
|
|
5793
6221
|
}
|
|
5794
6222
|
|
|
5795
|
-
var toolNames = ["get_all_schema", "get_source", "search_content", "validate_content", "create_patch", "add_session_image_to_gallery", "remove_image_gallery_entry", "navigate_to", "get_current_context", "get_patches", "get_source_path_from_route", "set_session_name", "show_compare_view", "ask_user_question", "duplicate_source", "empty_at_path", "count_entries", "get_record_keys"];
|
|
6223
|
+
var toolNames = ["get_all_schema", "get_source", "search_content", "validate_content", "create_patch", "add_session_image_to_gallery", "remove_image_gallery_entry", "navigate_to", "get_current_context", "get_patches", "get_source_path_from_route", "set_session_name", "show_compare_view", "ask_user_question", "duplicate_source", "empty_at_path", "count_entries", "get_record_keys", "list_sketchpads", "create_sketchpad", "read_sketchpad", "write_sketchpad"];
|
|
6224
|
+
|
|
6225
|
+
/**
|
|
6226
|
+
* A page sketch: a page written as indented text, with four primitives.
|
|
6227
|
+
*
|
|
6228
|
+
* ```
|
|
6229
|
+
* # Our people text (a heading: #, ## or ###)
|
|
6230
|
+
* We are 40 people in Oslo. text (a paragraph)
|
|
6231
|
+
* [image: Team photo] placeholder: [kind] or [kind: label]
|
|
6232
|
+
* [hero: Roof](image: /a.jpg) a placeholder with an image (or video) in it
|
|
6233
|
+
* icon hero M3 5h18v14H3z how every [hero] box is drawn: SVG path data
|
|
6234
|
+
* row its children side by side
|
|
6235
|
+
* col 2 its children stacked; 2 shares of the row
|
|
6236
|
+
* ## Design
|
|
6237
|
+
* col
|
|
6238
|
+
* [button: Join us]
|
|
6239
|
+
* ```
|
|
6240
|
+
*
|
|
6241
|
+
* It is a scratch pad, not a layout language: it says WHAT is on a page and
|
|
6242
|
+
* roughly WHERE, so an assistant and a person can agree on a page's content
|
|
6243
|
+
* before anyone worries about how it looks. The person never sees this text,
|
|
6244
|
+
* only the page it describes; the assistant never sees the page, only this.
|
|
6245
|
+
* So the two have to be the same thing, and the format is STRICT: there is
|
|
6246
|
+
* exactly one way to write what is on the screen. `checkSketch` is that
|
|
6247
|
+
* rule, and the server refuses a write that breaks it, with the line to fix.
|
|
6248
|
+
*
|
|
6249
|
+
* Parsing is still forgiving, so a sketch that breaks the rule shows what it
|
|
6250
|
+
* can rather than nothing; that is for reading, never for accepting.
|
|
6251
|
+
*
|
|
6252
|
+
* A placeholder's kind is any word, and nothing here knows what one means. The
|
|
6253
|
+
* assistant that writes the sketch also draws each kind's icon, as path data
|
|
6254
|
+
* in a 24 by 24 box, so a kind nobody thought of looks as deliberate as an
|
|
6255
|
+
* image. Media put in a box is written into the text too, so the assistant
|
|
6256
|
+
* that builds the page reads it exactly as the person left it.
|
|
6257
|
+
*/
|
|
6258
|
+
|
|
6259
|
+
var CONTAINER = /^(row|col)(?:\s+(\d+))?$/;
|
|
6260
|
+
var PLACEHOLDER = /^\[([^\]:]*)(?::([^\]]*))?\](?:\((image|video):\s*([^\s)]+)\s*\))?$/;
|
|
6261
|
+
var HAS_MEDIA = /^\[[^\]]*\]\(/;
|
|
6262
|
+
var ICON = /^icon\s+(\S+)\s+([Mm][\d\s.-].*)$/;
|
|
6263
|
+
var PATH_DATA = /^[Mm][MmLlHhVvCcSsQqTtAaZz\d\s.,-]*$/;
|
|
6264
|
+
var HEADING = /^(#{1,3})\s+(.*)$/;
|
|
6265
|
+
function parseSketch(source) {
|
|
6266
|
+
var blocks = [];
|
|
6267
|
+
var errors = [];
|
|
6268
|
+
var icons = {};
|
|
6269
|
+
// The containers that are open at the current line, innermost last.
|
|
6270
|
+
var stack = [{
|
|
6271
|
+
type: "page",
|
|
6272
|
+
indent: -1,
|
|
6273
|
+
children: blocks,
|
|
6274
|
+
lastIndent: null
|
|
6275
|
+
}];
|
|
6276
|
+
source.split(/\r?\n/).forEach(function (raw, index) {
|
|
6277
|
+
var line = index + 1;
|
|
6278
|
+
var expanded = raw.replace(/\t/g, " ");
|
|
6279
|
+
var content = expanded.trim();
|
|
6280
|
+
if (content === "") {
|
|
6281
|
+
return;
|
|
6282
|
+
}
|
|
6283
|
+
var indent = expanded.length - expanded.trimStart().length;
|
|
6284
|
+
|
|
6285
|
+
// An icon is not a block, so it can go anywhere and closes nothing.
|
|
6286
|
+
var icon = ICON.exec(content);
|
|
6287
|
+
if (icon) {
|
|
6288
|
+
var path = icon[2].trim();
|
|
6289
|
+
if (PATH_DATA.test(path)) {
|
|
6290
|
+
icons[icon[1].toLowerCase()] = path;
|
|
6291
|
+
} else {
|
|
6292
|
+
errors.push({
|
|
6293
|
+
line: line,
|
|
6294
|
+
message: 'An icon is SVG path data for a 24 by 24 box, like "icon stat M3 17l6-6 4 4 8-8". Only path commands and numbers are allowed.'
|
|
6295
|
+
});
|
|
6296
|
+
}
|
|
6297
|
+
return;
|
|
6298
|
+
}
|
|
6299
|
+
while (stack.length > 1 && indent <= stack[stack.length - 1].indent) {
|
|
6300
|
+
stack.pop();
|
|
6301
|
+
}
|
|
6302
|
+
var parent = stack[stack.length - 1];
|
|
6303
|
+
var node = parseContent(content, line, errors);
|
|
6304
|
+
|
|
6305
|
+
// Indented further than the block above it, and that block is not a
|
|
6306
|
+
// container. Keep it as that block's sibling rather than dropping it.
|
|
6307
|
+
if (parent.lastIndent !== null && indent > parent.lastIndent) {
|
|
6308
|
+
errors.push({
|
|
6309
|
+
line: line,
|
|
6310
|
+
message: "Only row and col can hold other blocks. Indent this as much as the line above it."
|
|
6311
|
+
});
|
|
6312
|
+
} else {
|
|
6313
|
+
parent.lastIndent = indent;
|
|
6314
|
+
}
|
|
6315
|
+
if (node.type === "col" && parent.type !== "row") {
|
|
6316
|
+
errors.push({
|
|
6317
|
+
line: line,
|
|
6318
|
+
message: "A col only goes directly inside a row."
|
|
6319
|
+
});
|
|
6320
|
+
}
|
|
6321
|
+
if (node.type === "row" && parent.type === "row") {
|
|
6322
|
+
errors.push({
|
|
6323
|
+
line: line,
|
|
6324
|
+
message: "A row goes in a col, not directly in another row."
|
|
6325
|
+
});
|
|
6326
|
+
}
|
|
6327
|
+
parent.children.push(node);
|
|
6328
|
+
if (node.type === "row" || node.type === "col") {
|
|
6329
|
+
stack.push({
|
|
6330
|
+
type: node.type,
|
|
6331
|
+
indent: indent,
|
|
6332
|
+
children: node.children,
|
|
6333
|
+
lastIndent: null
|
|
6334
|
+
});
|
|
6335
|
+
}
|
|
6336
|
+
});
|
|
6337
|
+
return {
|
|
6338
|
+
blocks: blocks,
|
|
6339
|
+
icons: icons,
|
|
6340
|
+
errors: errors
|
|
6341
|
+
};
|
|
6342
|
+
}
|
|
6343
|
+
function parseContent(content, line, errors) {
|
|
6344
|
+
// A leading backslash keeps a line that looks like a keyword as text.
|
|
6345
|
+
if (content.startsWith("\\")) {
|
|
6346
|
+
return {
|
|
6347
|
+
type: "text",
|
|
6348
|
+
line: line,
|
|
6349
|
+
level: 0,
|
|
6350
|
+
text: content.slice(1)
|
|
6351
|
+
};
|
|
6352
|
+
}
|
|
6353
|
+
var container = CONTAINER.exec(content);
|
|
6354
|
+
if (container) {
|
|
6355
|
+
if (container[1] === "row") {
|
|
6356
|
+
if (container[2] !== undefined) {
|
|
6357
|
+
errors.push({
|
|
6358
|
+
line: line,
|
|
6359
|
+
message: "A row takes no number. Put it on a col: \"col ".concat(container[2], "\".")
|
|
6360
|
+
});
|
|
6361
|
+
}
|
|
6362
|
+
return {
|
|
6363
|
+
type: "row",
|
|
6364
|
+
line: line,
|
|
6365
|
+
children: []
|
|
6366
|
+
};
|
|
6367
|
+
}
|
|
6368
|
+
var weight = container[2] === undefined ? 1 : Number(container[2]);
|
|
6369
|
+
if (weight === 0) {
|
|
6370
|
+
errors.push({
|
|
6371
|
+
line: line,
|
|
6372
|
+
message: "A col needs a weight of 1 or more."
|
|
6373
|
+
});
|
|
6374
|
+
}
|
|
6375
|
+
return {
|
|
6376
|
+
type: "col",
|
|
6377
|
+
line: line,
|
|
6378
|
+
weight: Math.max(weight, 1),
|
|
6379
|
+
children: []
|
|
6380
|
+
};
|
|
6381
|
+
}
|
|
6382
|
+
if (content.startsWith("[")) {
|
|
6383
|
+
var placeholder = PLACEHOLDER.exec(content);
|
|
6384
|
+
if (placeholder) {
|
|
6385
|
+
var _placeholder$;
|
|
6386
|
+
var kind = placeholder[1].trim();
|
|
6387
|
+
var label = (_placeholder$ = placeholder[2]) === null || _placeholder$ === void 0 ? void 0 : _placeholder$.trim();
|
|
6388
|
+
if (/\s/.test(kind)) {
|
|
6389
|
+
// An icon line names a kind by one word, so a kind has to be one.
|
|
6390
|
+
errors.push({
|
|
6391
|
+
line: line,
|
|
6392
|
+
message: "A box's kind is one word: \"[".concat(kind.replace(/\s+/g, "-")).concat(label ? ": ".concat(label) : "", "]\".")
|
|
6393
|
+
});
|
|
6394
|
+
}
|
|
6395
|
+
var mediaType = placeholder[3];
|
|
6396
|
+
return {
|
|
6397
|
+
type: "placeholder",
|
|
6398
|
+
line: line,
|
|
6399
|
+
kind: kind === "" ? "block" : kind,
|
|
6400
|
+
label: label ? label : null,
|
|
6401
|
+
media: mediaType === "image" || mediaType === "video" ? {
|
|
6402
|
+
type: mediaType,
|
|
6403
|
+
src: placeholder[4]
|
|
6404
|
+
} : null
|
|
6405
|
+
};
|
|
6406
|
+
}
|
|
6407
|
+
if (HAS_MEDIA.test(content)) {
|
|
6408
|
+
errors.push({
|
|
6409
|
+
line: line,
|
|
6410
|
+
message: 'Media in a box is written after it as (image: url) or (video: url), like "[hero: Team photo](image: /public/val/team.jpg)".'
|
|
6411
|
+
});
|
|
6412
|
+
return {
|
|
6413
|
+
type: "text",
|
|
6414
|
+
line: line,
|
|
6415
|
+
level: 0,
|
|
6416
|
+
text: content
|
|
6417
|
+
};
|
|
6418
|
+
}
|
|
6419
|
+
errors.push({
|
|
6420
|
+
line: line,
|
|
6421
|
+
message: 'A placeholder is written [kind] or [kind: label], on a line of its own, like "[image: Team photo]".'
|
|
6422
|
+
});
|
|
6423
|
+
return {
|
|
6424
|
+
type: "text",
|
|
6425
|
+
line: line,
|
|
6426
|
+
level: 0,
|
|
6427
|
+
text: content
|
|
6428
|
+
};
|
|
6429
|
+
}
|
|
6430
|
+
var heading = HEADING.exec(content);
|
|
6431
|
+
if (heading) {
|
|
6432
|
+
var level = heading[1].length === 1 ? 1 : heading[1].length === 2 ? 2 : 3;
|
|
6433
|
+
return {
|
|
6434
|
+
type: "text",
|
|
6435
|
+
line: line,
|
|
6436
|
+
level: level,
|
|
6437
|
+
text: heading[2]
|
|
6438
|
+
};
|
|
6439
|
+
}
|
|
6440
|
+
return {
|
|
6441
|
+
type: "text",
|
|
6442
|
+
line: line,
|
|
6443
|
+
level: 0,
|
|
6444
|
+
text: content
|
|
6445
|
+
};
|
|
6446
|
+
}
|
|
6447
|
+
|
|
6448
|
+
/**
|
|
6449
|
+
* The line a text block is written as. Line breaks become spaces, and a
|
|
6450
|
+
* paragraph that would read as something else is kept as text with `\`.
|
|
6451
|
+
*/
|
|
6452
|
+
function formatSketchText(level, text) {
|
|
6453
|
+
var flat = text.replace(/\s+/g, " ").trim();
|
|
6454
|
+
if (level > 0) {
|
|
6455
|
+
return "#".repeat(level) + " " + flat;
|
|
6456
|
+
}
|
|
6457
|
+
var ambiguous = flat.startsWith("\\") || flat.startsWith("[") || CONTAINER.test(flat) || HEADING.test(flat) || ICON.test(flat);
|
|
6458
|
+
return ambiguous ? "\\" + flat : flat;
|
|
6459
|
+
}
|
|
6460
|
+
|
|
6461
|
+
/** The line a placeholder is written as. */
|
|
6462
|
+
function formatSketchBox(placeholder) {
|
|
6463
|
+
var clean = function clean(text) {
|
|
6464
|
+
return text.replace(/[[\]]/g, "").replace(/\s+/g, " ").trim();
|
|
6465
|
+
};
|
|
6466
|
+
var kind = clean(placeholder.kind).replace(/:/g, "") || "block";
|
|
6467
|
+
var label = placeholder.label === null ? "" : clean(placeholder.label);
|
|
6468
|
+
var media = placeholder.media ? "(".concat(placeholder.media.type, ": ").concat(placeholder.media.src.replace(/[\s)]/g, encodeURIComponent), ")") : "";
|
|
6469
|
+
return "[".concat(kind).concat(label ? ": ".concat(label) : "", "]").concat(media);
|
|
6470
|
+
}
|
|
6471
|
+
|
|
6472
|
+
/**
|
|
6473
|
+
* The ONE way of writing `blocks` and `icons`: what `checkSketch` holds every
|
|
6474
|
+
* other text to, and what the Studio's editor writes (its own serializer is
|
|
6475
|
+
* tested against this one). Two spaces per level; an empty row gets an empty
|
|
6476
|
+
* col, so it has somewhere to type; a col outside a row is written as its
|
|
6477
|
+
* contents, which is all it shows; the icons last, after one blank line, and
|
|
6478
|
+
* no blank line anywhere else; a final newline. Empty text is not written --
|
|
6479
|
+
* it is not on the page.
|
|
6480
|
+
*/
|
|
6481
|
+
function formatSketch(blocks, icons) {
|
|
6482
|
+
var lines = [];
|
|
6483
|
+
var _walk = function walk(node, depth, inRow) {
|
|
6484
|
+
var indent = " ".repeat(depth);
|
|
6485
|
+
switch (node.type) {
|
|
6486
|
+
case "text":
|
|
6487
|
+
if (node.text) {
|
|
6488
|
+
lines.push(indent + formatSketchText(node.level, node.text));
|
|
6489
|
+
}
|
|
6490
|
+
return;
|
|
6491
|
+
case "placeholder":
|
|
6492
|
+
lines.push(indent + formatSketchBox(node));
|
|
6493
|
+
return;
|
|
6494
|
+
case "row":
|
|
6495
|
+
lines.push(indent + "row");
|
|
6496
|
+
if (node.children.length === 0) {
|
|
6497
|
+
lines.push(indent + " col");
|
|
6498
|
+
}
|
|
6499
|
+
node.children.forEach(function (child) {
|
|
6500
|
+
return _walk(child, depth + 1, true);
|
|
6501
|
+
});
|
|
6502
|
+
return;
|
|
6503
|
+
case "col":
|
|
6504
|
+
if (!inRow) {
|
|
6505
|
+
node.children.forEach(function (child) {
|
|
6506
|
+
return _walk(child, depth, false);
|
|
6507
|
+
});
|
|
6508
|
+
return;
|
|
6509
|
+
}
|
|
6510
|
+
lines.push(indent + (node.weight === 1 ? "col" : "col ".concat(node.weight)));
|
|
6511
|
+
node.children.forEach(function (child) {
|
|
6512
|
+
return _walk(child, depth + 1, false);
|
|
6513
|
+
});
|
|
6514
|
+
return;
|
|
6515
|
+
}
|
|
6516
|
+
};
|
|
6517
|
+
blocks.forEach(function (block) {
|
|
6518
|
+
return _walk(block, 0, false);
|
|
6519
|
+
});
|
|
6520
|
+
var iconLines = Object.entries(icons).map(function (_ref) {
|
|
6521
|
+
var _ref2 = createForOfIteratorHelper._slicedToArray(_ref, 2),
|
|
6522
|
+
kind = _ref2[0],
|
|
6523
|
+
path = _ref2[1];
|
|
6524
|
+
return "icon ".concat(kind, " ").concat(path);
|
|
6525
|
+
});
|
|
6526
|
+
var all = [].concat(lines, createForOfIteratorHelper._toConsumableArray(iconLines.length > 0 ? [""].concat(createForOfIteratorHelper._toConsumableArray(iconLines)) : []));
|
|
6527
|
+
return all.length > 0 ? all.join("\n") + "\n" : "";
|
|
6528
|
+
}
|
|
6529
|
+
|
|
6530
|
+
/**
|
|
6531
|
+
* What a list names a sketch by: its first top-level heading, the biggest
|
|
6532
|
+
* one first. Null for a sketch with no heading, which a list then names by
|
|
6533
|
+
* its page.
|
|
6534
|
+
*/
|
|
6535
|
+
function sketchTitle(blocks) {
|
|
6536
|
+
var _loop = function _loop() {
|
|
6537
|
+
var level = _arr[_i];
|
|
6538
|
+
var heading = blocks.find(function (block) {
|
|
6539
|
+
return block.type === "text" && block.level === level && block.text !== "";
|
|
6540
|
+
});
|
|
6541
|
+
if (heading) {
|
|
6542
|
+
return {
|
|
6543
|
+
v: heading.text
|
|
6544
|
+
};
|
|
6545
|
+
}
|
|
6546
|
+
},
|
|
6547
|
+
_ret;
|
|
6548
|
+
for (var _i = 0, _arr = [1, 2, 3]; _i < _arr.length; _i++) {
|
|
6549
|
+
_ret = _loop();
|
|
6550
|
+
if (_ret) return _ret.v;
|
|
6551
|
+
}
|
|
6552
|
+
return null;
|
|
6553
|
+
}
|
|
6554
|
+
|
|
6555
|
+
/**
|
|
6556
|
+
* Everything wrong with `source`, or nothing when it is a sketch exactly as
|
|
6557
|
+
* `formatSketch` writes it.
|
|
6558
|
+
*
|
|
6559
|
+
* Strict on purpose. The person sees the page and the assistant sees the
|
|
6560
|
+
* text, so a text with two spellings of one page -- a tab or two spaces, an
|
|
6561
|
+
* icon line here or there, a blank line or none -- is a text the assistant
|
|
6562
|
+
* cannot trust to be what is on the screen, and that would show it a change
|
|
6563
|
+
* nobody made the next time the Studio writes it back. Holding every write
|
|
6564
|
+
* to the one spelling rules all of that out at once.
|
|
6565
|
+
*
|
|
6566
|
+
* The parse errors come first; past those, the first line that is spelled
|
|
6567
|
+
* differently, with how it should be spelled.
|
|
6568
|
+
*/
|
|
6569
|
+
function checkSketch(source) {
|
|
6570
|
+
var _parseSketch = parseSketch(source),
|
|
6571
|
+
blocks = _parseSketch.blocks,
|
|
6572
|
+
icons = _parseSketch.icons,
|
|
6573
|
+
errors = _parseSketch.errors;
|
|
6574
|
+
if (errors.length > 0) {
|
|
6575
|
+
return errors;
|
|
6576
|
+
}
|
|
6577
|
+
var canonical = formatSketch(blocks, icons);
|
|
6578
|
+
if (canonical === source) {
|
|
6579
|
+
return [];
|
|
6580
|
+
}
|
|
6581
|
+
if (canonical !== "" && !source.endsWith("\n")) {
|
|
6582
|
+
return [{
|
|
6583
|
+
line: source.split("\n").length,
|
|
6584
|
+
message: "A sketch ends with a newline."
|
|
6585
|
+
}];
|
|
6586
|
+
}
|
|
6587
|
+
// Compared without the final newline, so an extra one is an extra line.
|
|
6588
|
+
var given = source.slice(0, -1).split("\n");
|
|
6589
|
+
var wanted = canonical.slice(0, -1).split("\n");
|
|
6590
|
+
for (var i = 0; i < Math.max(given.length, wanted.length); i++) {
|
|
6591
|
+
if (given[i] !== wanted[i]) {
|
|
6592
|
+
return [{
|
|
6593
|
+
line: i + 1,
|
|
6594
|
+
message: wanted[i] === undefined ? "Nothing goes here: the sketch ends on the line before." : given[i] === "" ? "No blank lines: the one blank line in a sketch is before its icons." : given[i] === undefined ? "The sketch goes on: \"".concat(wanted[i], "\".") : "This line is written ".concat(JSON.stringify(wanted[i]), " in a sketch: two spaces per level, the icons last after one blank line, and no other blank lines.")
|
|
6595
|
+
}];
|
|
6596
|
+
}
|
|
6597
|
+
}
|
|
6598
|
+
return [];
|
|
6599
|
+
}
|
|
5796
6600
|
|
|
5797
6601
|
function buildFileRefValue(filePath, metadata) {
|
|
5798
6602
|
return createForOfIteratorHelper._objectSpread2({
|
|
@@ -8785,6 +9589,7 @@ exports.parseRoutePattern = getSitemapTree.parseRoutePattern;
|
|
|
8785
9589
|
exports.quickPreviewSiteOrigin = getSitemapTree.quickPreviewSiteOrigin;
|
|
8786
9590
|
exports.readPageSnapshot = getSitemapTree.readPageSnapshot;
|
|
8787
9591
|
exports.restoreScroll = getSitemapTree.restoreScroll;
|
|
9592
|
+
exports.screenshotPage = getSitemapTree.screenshotPage;
|
|
8788
9593
|
exports.startElementPicking = getSitemapTree.startElementPicking;
|
|
8789
9594
|
exports.storeQuickPreview = getSitemapTree.storeQuickPreview;
|
|
8790
9595
|
exports.watchPageLocation = getSitemapTree.watchPageLocation;
|
|
@@ -8839,6 +9644,7 @@ exports.RestoreVerdict = RestoreVerdict;
|
|
|
8839
9644
|
exports.RichTextOptions = RichTextOptions;
|
|
8840
9645
|
exports.SCHEMA_SOURCE_FIXES = SCHEMA_SOURCE_FIXES;
|
|
8841
9646
|
exports.SELF_CHECK_VERSION = SELF_CHECK_VERSION;
|
|
9647
|
+
exports.SKETCHPAD_MAX_TEXT_LENGTH = SKETCHPAD_MAX_TEXT_LENGTH;
|
|
8842
9648
|
exports.STUDIO_FIXES = STUDIO_FIXES;
|
|
8843
9649
|
exports.SerializedArraySchema = SerializedArraySchema;
|
|
8844
9650
|
exports.SerializedBooleanSchema = SerializedBooleanSchema;
|
|
@@ -8864,6 +9670,8 @@ exports.SerializedStringSchema = SerializedStringSchema;
|
|
|
8864
9670
|
exports.SerializedValViewSchema = SerializedValViewSchema;
|
|
8865
9671
|
exports.SerializedVideoSchema = SerializedVideoSchema;
|
|
8866
9672
|
exports.SharedValConfig = SharedValConfig;
|
|
9673
|
+
exports.Sketchpad = Sketchpad;
|
|
9674
|
+
exports.SketchpadSummary = SketchpadSummary;
|
|
8867
9675
|
exports.VAL_ENABLE_COOKIE_NAME = VAL_ENABLE_COOKIE_NAME;
|
|
8868
9676
|
exports.VAL_GREEN_RAMP = VAL_GREEN_RAMP;
|
|
8869
9677
|
exports.VAL_SESSION_COOKIE = VAL_SESSION_COOKIE;
|
|
@@ -8884,6 +9692,8 @@ exports.buildRemoveImageGalleryEntryPatch = buildRemoveImageGalleryEntryPatch;
|
|
|
8884
9692
|
exports.buildSearchIndex = buildSearchIndex;
|
|
8885
9693
|
exports.chainHeadOf = chainHeadOf;
|
|
8886
9694
|
exports.checkCompatibility = checkCompatibility;
|
|
9695
|
+
exports.checkSketch = checkSketch;
|
|
9696
|
+
exports.childSource = childSource;
|
|
8887
9697
|
exports.chooseEncoded = chooseEncoded;
|
|
8888
9698
|
exports.concatModulePath = concatModulePath;
|
|
8889
9699
|
exports.contrastRatio = contrastRatio;
|
|
@@ -8902,6 +9712,9 @@ exports.findSimilar = findSimilar;
|
|
|
8902
9712
|
exports.fitWithin = fitWithin;
|
|
8903
9713
|
exports.flattenRichText = flattenRichText;
|
|
8904
9714
|
exports.forEachRichTextImage = forEachRichTextImage;
|
|
9715
|
+
exports.formatSketch = formatSketch;
|
|
9716
|
+
exports.formatSketchBox = formatSketchBox;
|
|
9717
|
+
exports.formatSketchText = formatSketchText;
|
|
8905
9718
|
exports.getErrorMessageFromUnknownJson = getErrorMessageFromUnknownJson;
|
|
8906
9719
|
exports.getFilenameFromRef = getFilenameFromRef;
|
|
8907
9720
|
exports.getInlineImgInfo = getInlineImgInfo;
|
|
@@ -8911,8 +9724,10 @@ exports.getRoutesOf = getRoutesOf;
|
|
|
8911
9724
|
exports.getRoutesWithModulePaths = getRoutesWithModulePaths;
|
|
8912
9725
|
exports.getSourceAt = getSourceAt;
|
|
8913
9726
|
exports.getValDemo = getValDemo;
|
|
9727
|
+
exports.hasLocaleRouteParam = hasLocaleRouteParam;
|
|
8914
9728
|
exports.indexModule = indexModule;
|
|
8915
9729
|
exports.isInsidePatchSetPath = isInsidePatchSetPath;
|
|
9730
|
+
exports.isJsonObject = isJsonObject;
|
|
8916
9731
|
exports.isLocaleSchema = isLocaleSchema;
|
|
8917
9732
|
exports.isMimeTypeAccepted = isMimeTypeAccepted;
|
|
8918
9733
|
exports.isRemoteSchema = isRemoteSchema;
|
|
@@ -8927,12 +9742,18 @@ exports.keyOfRecordPath = keyOfRecordPath;
|
|
|
8927
9742
|
exports.levenshtein = levenshtein;
|
|
8928
9743
|
exports.localeAt = localeAt;
|
|
8929
9744
|
exports.localeMeantBy = localeMeantBy;
|
|
9745
|
+
exports.localeOfModuleRoot = localeOfModuleRoot;
|
|
9746
|
+
exports.localeOfRouteKey = localeOfRouteKey;
|
|
9747
|
+
exports.localeParamOfRouteKey = localeParamOfRouteKey;
|
|
9748
|
+
exports.localeScopeAt = localeScopeAt;
|
|
8930
9749
|
exports.memoizePerRequest = memoizePerRequest;
|
|
8931
9750
|
exports.newestCommitSha = newestCommitSha;
|
|
9751
|
+
exports.parseSketch = parseSketch;
|
|
8932
9752
|
exports.partitionValidationErrors = partitionValidationErrors;
|
|
8933
9753
|
exports.performSearch = performSearch;
|
|
8934
9754
|
exports.proposalCustomProperties = proposalCustomProperties;
|
|
8935
9755
|
exports.relativeLuminance = relativeLuminance;
|
|
9756
|
+
exports.relocateForLocale = relocateForLocale;
|
|
8936
9757
|
exports.remirrorToRichTextSource = remirrorToRichTextSource;
|
|
8937
9758
|
exports.removeModule = removeModule;
|
|
8938
9759
|
exports.resolveEncodeSettings = resolveEncodeSettings;
|
|
@@ -8950,6 +9771,7 @@ exports.selfCheck = selfCheck;
|
|
|
8950
9771
|
exports.shouldEncodeWithWasm = shouldEncodeWithWasm;
|
|
8951
9772
|
exports.sideFiles = sideFiles;
|
|
8952
9773
|
exports.sideSource = sideSource;
|
|
9774
|
+
exports.sketchTitle = sketchTitle;
|
|
8953
9775
|
exports.sourcePathOfChild = sourcePathOfChild;
|
|
8954
9776
|
exports.themeCustomProperties = themeCustomProperties;
|
|
8955
9777
|
exports.toolNames = toolNames;
|