@wildwinter/toolkit 0.2.5 → 0.2.6
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 +10 -0
- package/conformance/extensions/manifest.json +232 -0
- package/dist/extensions.cjs +73 -1
- package/dist/extensions.cjs.map +1 -1
- package/dist/extensions.d.cts +23 -1
- package/dist/extensions.d.ts +23 -1
- package/dist/extensions.js +72 -2
- package/dist/extensions.js.map +1 -1
- package/extensions.md +22 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @wildwinter/toolkit
|
|
2
2
|
|
|
3
|
+
## 0.2.6
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Views and reads in a manifest** (`./extensions`, tier 2): `views` declares the web components an extension's
|
|
8
|
+
installed package supplies, each with an `id`, a `name`, an `entry` script inside the package, the custom `element`
|
|
9
|
+
it defines, and optionally the `hosts` that offer it; `reads` names the other extensions whose data the views read.
|
|
10
|
+
The manifest check holds both to their shape. `viewsFor(manifest, host)` lists the views a host offers, and
|
|
11
|
+
`isViewEntry` keeps an entry inside its package.
|
|
12
|
+
|
|
3
13
|
## 0.2.5
|
|
4
14
|
|
|
5
15
|
### Added
|
|
@@ -1438,6 +1438,238 @@
|
|
|
1438
1438
|
"code": "default-misfit"
|
|
1439
1439
|
}
|
|
1440
1440
|
]
|
|
1441
|
+
},
|
|
1442
|
+
{
|
|
1443
|
+
"name": "views and reads pass",
|
|
1444
|
+
"manifest": {
|
|
1445
|
+
"schema": "wildwinter/extension@0",
|
|
1446
|
+
"id": "probe",
|
|
1447
|
+
"name": "Probe",
|
|
1448
|
+
"version": "1.0.0",
|
|
1449
|
+
"targets": {
|
|
1450
|
+
"patter": {
|
|
1451
|
+
"line": {
|
|
1452
|
+
"fields": [
|
|
1453
|
+
{
|
|
1454
|
+
"name": "mood",
|
|
1455
|
+
"type": "text"
|
|
1456
|
+
}
|
|
1457
|
+
]
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
},
|
|
1461
|
+
"views": [
|
|
1462
|
+
{
|
|
1463
|
+
"id": "sheet",
|
|
1464
|
+
"name": "Sheet",
|
|
1465
|
+
"entry": "view/sheet.js",
|
|
1466
|
+
"element": "probe-sheet"
|
|
1467
|
+
},
|
|
1468
|
+
{
|
|
1469
|
+
"id": "cards",
|
|
1470
|
+
"name": "Cards",
|
|
1471
|
+
"entry": "cards.js",
|
|
1472
|
+
"element": "probe-cards",
|
|
1473
|
+
"hosts": [
|
|
1474
|
+
"patter"
|
|
1475
|
+
]
|
|
1476
|
+
}
|
|
1477
|
+
],
|
|
1478
|
+
"reads": [
|
|
1479
|
+
"patterstage"
|
|
1480
|
+
]
|
|
1481
|
+
},
|
|
1482
|
+
"problems": []
|
|
1483
|
+
},
|
|
1484
|
+
{
|
|
1485
|
+
"name": "a view's shape is checked",
|
|
1486
|
+
"manifest": {
|
|
1487
|
+
"schema": "wildwinter/extension@0",
|
|
1488
|
+
"id": "probe",
|
|
1489
|
+
"name": "Probe",
|
|
1490
|
+
"version": "1.0.0",
|
|
1491
|
+
"targets": {
|
|
1492
|
+
"patter": {
|
|
1493
|
+
"line": {
|
|
1494
|
+
"fields": [
|
|
1495
|
+
{
|
|
1496
|
+
"name": "mood",
|
|
1497
|
+
"type": "text"
|
|
1498
|
+
}
|
|
1499
|
+
]
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
},
|
|
1503
|
+
"views": [
|
|
1504
|
+
{
|
|
1505
|
+
"id": "Sheet",
|
|
1506
|
+
"name": " ",
|
|
1507
|
+
"entry": "../sheet.js",
|
|
1508
|
+
"element": "sheet",
|
|
1509
|
+
"colour": "red"
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
"id": "two",
|
|
1513
|
+
"name": "Two",
|
|
1514
|
+
"entry": "/abs/two.js",
|
|
1515
|
+
"element": "Probe-Two",
|
|
1516
|
+
"hosts": []
|
|
1517
|
+
},
|
|
1518
|
+
{
|
|
1519
|
+
"id": "three",
|
|
1520
|
+
"name": "Three",
|
|
1521
|
+
"entry": "view\\three.js",
|
|
1522
|
+
"element": "probe-three",
|
|
1523
|
+
"hosts": [
|
|
1524
|
+
"ink",
|
|
1525
|
+
"storylets"
|
|
1526
|
+
]
|
|
1527
|
+
},
|
|
1528
|
+
{
|
|
1529
|
+
"id": "three",
|
|
1530
|
+
"name": "Again",
|
|
1531
|
+
"entry": "view/again.mjs",
|
|
1532
|
+
"element": "probe-three"
|
|
1533
|
+
}
|
|
1534
|
+
]
|
|
1535
|
+
},
|
|
1536
|
+
"problems": [
|
|
1537
|
+
{
|
|
1538
|
+
"path": "views[0].colour",
|
|
1539
|
+
"code": "unknown-key",
|
|
1540
|
+
"severity": "warning"
|
|
1541
|
+
},
|
|
1542
|
+
{
|
|
1543
|
+
"path": "views[0].id",
|
|
1544
|
+
"code": "view-id"
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
"path": "views[0].name",
|
|
1548
|
+
"code": "view-name"
|
|
1549
|
+
},
|
|
1550
|
+
{
|
|
1551
|
+
"path": "views[0].entry",
|
|
1552
|
+
"code": "view-entry"
|
|
1553
|
+
},
|
|
1554
|
+
{
|
|
1555
|
+
"path": "views[0].element",
|
|
1556
|
+
"code": "view-element"
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
"path": "views[1].entry",
|
|
1560
|
+
"code": "view-entry"
|
|
1561
|
+
},
|
|
1562
|
+
{
|
|
1563
|
+
"path": "views[1].element",
|
|
1564
|
+
"code": "view-element"
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
"path": "views[1].hosts",
|
|
1568
|
+
"code": "view-hosts"
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
"path": "views[2].entry",
|
|
1572
|
+
"code": "view-entry"
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
"path": "views[2].hosts[0]",
|
|
1576
|
+
"code": "unknown-host"
|
|
1577
|
+
},
|
|
1578
|
+
{
|
|
1579
|
+
"path": "views[2].hosts[1]",
|
|
1580
|
+
"code": "view-host-untargeted",
|
|
1581
|
+
"severity": "warning"
|
|
1582
|
+
},
|
|
1583
|
+
{
|
|
1584
|
+
"path": "views[3].id",
|
|
1585
|
+
"code": "view-duplicate"
|
|
1586
|
+
},
|
|
1587
|
+
{
|
|
1588
|
+
"path": "views[3].entry",
|
|
1589
|
+
"code": "view-entry"
|
|
1590
|
+
},
|
|
1591
|
+
{
|
|
1592
|
+
"path": "views[3].element",
|
|
1593
|
+
"code": "view-duplicate"
|
|
1594
|
+
}
|
|
1595
|
+
]
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
"name": "reads name other extensions, once each",
|
|
1599
|
+
"manifest": {
|
|
1600
|
+
"schema": "wildwinter/extension@0",
|
|
1601
|
+
"id": "probe",
|
|
1602
|
+
"name": "Probe",
|
|
1603
|
+
"version": "1.0.0",
|
|
1604
|
+
"targets": {
|
|
1605
|
+
"patter": {
|
|
1606
|
+
"line": {
|
|
1607
|
+
"fields": [
|
|
1608
|
+
{
|
|
1609
|
+
"name": "mood",
|
|
1610
|
+
"type": "text"
|
|
1611
|
+
}
|
|
1612
|
+
]
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
},
|
|
1616
|
+
"reads": [
|
|
1617
|
+
"patterstage",
|
|
1618
|
+
"probe",
|
|
1619
|
+
"patterstage",
|
|
1620
|
+
"Bad"
|
|
1621
|
+
]
|
|
1622
|
+
},
|
|
1623
|
+
"problems": [
|
|
1624
|
+
{
|
|
1625
|
+
"path": "reads[1]",
|
|
1626
|
+
"code": "reads-self",
|
|
1627
|
+
"severity": "warning"
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
"path": "reads[2]",
|
|
1631
|
+
"code": "reads-duplicate"
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
"path": "reads[3]",
|
|
1635
|
+
"code": "reads-id"
|
|
1636
|
+
}
|
|
1637
|
+
]
|
|
1638
|
+
},
|
|
1639
|
+
{
|
|
1640
|
+
"name": "views and reads must be lists",
|
|
1641
|
+
"manifest": {
|
|
1642
|
+
"schema": "wildwinter/extension@0",
|
|
1643
|
+
"id": "probe",
|
|
1644
|
+
"name": "Probe",
|
|
1645
|
+
"version": "1.0.0",
|
|
1646
|
+
"targets": {
|
|
1647
|
+
"patter": {
|
|
1648
|
+
"line": {
|
|
1649
|
+
"fields": [
|
|
1650
|
+
{
|
|
1651
|
+
"name": "mood",
|
|
1652
|
+
"type": "text"
|
|
1653
|
+
}
|
|
1654
|
+
]
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
"views": {
|
|
1659
|
+
"id": "sheet"
|
|
1660
|
+
},
|
|
1661
|
+
"reads": "patterstage"
|
|
1662
|
+
},
|
|
1663
|
+
"problems": [
|
|
1664
|
+
{
|
|
1665
|
+
"path": "views",
|
|
1666
|
+
"code": "not-a-list"
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
"path": "reads",
|
|
1670
|
+
"code": "not-a-list"
|
|
1671
|
+
}
|
|
1672
|
+
]
|
|
1441
1673
|
}
|
|
1442
1674
|
]
|
|
1443
1675
|
}
|
package/dist/extensions.cjs
CHANGED
|
@@ -370,7 +370,9 @@ var TYPE_KEYS = ["type", "values", "stages", "renamedStages", "to", "from", "fie
|
|
|
370
370
|
var FIELD_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "name", "label", "help", "required", "group", "editorOnly"]);
|
|
371
371
|
var CLAIM_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "setting", "label", "help", "required"]);
|
|
372
372
|
var BARE_KEYS = new Set(TYPE_KEYS);
|
|
373
|
-
var MANIFEST_KEYS = /* @__PURE__ */ new Set(["schema", "id", "name", "version", "docs", "settings", "targets"]);
|
|
373
|
+
var MANIFEST_KEYS = /* @__PURE__ */ new Set(["schema", "id", "name", "version", "docs", "settings", "targets", "views", "reads"]);
|
|
374
|
+
var VIEW_KEYS = /* @__PURE__ */ new Set(["id", "name", "entry", "element", "hosts"]);
|
|
375
|
+
var ELEMENT = /^[a-z][a-z0-9._]*-[a-z0-9._-]*$/;
|
|
374
376
|
var err2 = (code, path, message) => ({ severity: "error", code, path, message });
|
|
375
377
|
function parseManifest(text) {
|
|
376
378
|
return parseSource(text);
|
|
@@ -392,6 +394,8 @@ function manifestProblems(manifest) {
|
|
|
392
394
|
}
|
|
393
395
|
if (m["docs"] !== void 0 && typeof m["docs"] !== "string") out.push(err2("docs", "docs", "docs is a link, as text"));
|
|
394
396
|
const settings = settingsProblems(m["settings"], out);
|
|
397
|
+
viewsProblems(m["views"], m["targets"], out);
|
|
398
|
+
readsProblems(m["reads"], m["id"], out);
|
|
395
399
|
const targets = m["targets"];
|
|
396
400
|
if (!isObject(targets) || Object.keys(targets).length === 0) {
|
|
397
401
|
out.push(err2("no-targets", "targets", "the manifest targets no host"));
|
|
@@ -490,6 +494,72 @@ function pickListProblems(kinds, hostPath, out) {
|
|
|
490
494
|
target["fields"].forEach((f, i) => walk(f, atIndex(atKey(atKey(hostPath, kind), "fields"), i)));
|
|
491
495
|
}
|
|
492
496
|
}
|
|
497
|
+
function isViewEntry(entry) {
|
|
498
|
+
if (typeof entry !== "string" || !entry.endsWith(".js") || entry.includes("\\")) return false;
|
|
499
|
+
const parts = entry.split("/");
|
|
500
|
+
return parts.every((p) => p !== "" && p !== "." && p !== "..");
|
|
501
|
+
}
|
|
502
|
+
function viewsProblems(views, targets, out) {
|
|
503
|
+
if (views === void 0) return;
|
|
504
|
+
if (!Array.isArray(views)) {
|
|
505
|
+
out.push(err2("not-a-list", "views", "views are a list"));
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const ids = /* @__PURE__ */ new Set();
|
|
509
|
+
const elements = /* @__PURE__ */ new Set();
|
|
510
|
+
const targeted = isObject(targets) ? Object.keys(targets) : [];
|
|
511
|
+
views.forEach((v, i) => {
|
|
512
|
+
const at = atIndex("views", i);
|
|
513
|
+
if (!isObject(v)) {
|
|
514
|
+
out.push(err2("not-an-object", at, "a view is an object"));
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
unknownKeys(v, VIEW_KEYS, at, out);
|
|
518
|
+
const id = v["id"];
|
|
519
|
+
if (typeof id !== "string" || !ID.test(id)) out.push(err2("view-id", atKey(at, "id"), "a view's id is lower case letters, digits and hyphens, starting with a letter"));
|
|
520
|
+
else if (ids.has(id)) out.push(err2("view-duplicate", atKey(at, "id"), `two views are called "${id}"`));
|
|
521
|
+
else ids.add(id);
|
|
522
|
+
if (typeof v["name"] !== "string" || v["name"].trim() === "") out.push(err2("view-name", atKey(at, "name"), "a view has a name, shown as its window's title"));
|
|
523
|
+
if (!isViewEntry(v["entry"])) {
|
|
524
|
+
out.push(err2("view-entry", atKey(at, "entry"), "a view's entry is a .js file in the extension's package, as a relative path such as view/sheet.js"));
|
|
525
|
+
}
|
|
526
|
+
const element = v["element"];
|
|
527
|
+
if (typeof element !== "string" || !ELEMENT.test(element)) {
|
|
528
|
+
out.push(err2("view-element", atKey(at, "element"), "a view's element is a custom element name: lower case, starting with a letter, with a hyphen, such as probe-view"));
|
|
529
|
+
} else if (elements.has(element)) out.push(err2("view-duplicate", atKey(at, "element"), `two views define <${element}>`));
|
|
530
|
+
else elements.add(element);
|
|
531
|
+
const hosts = v["hosts"];
|
|
532
|
+
if (hosts === void 0) return;
|
|
533
|
+
if (!Array.isArray(hosts) || hosts.length === 0) {
|
|
534
|
+
out.push(err2("view-hosts", atKey(at, "hosts"), "a view's hosts are a list of at least one host"));
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
hosts.forEach((h, j) => {
|
|
538
|
+
const hp = atIndex(atKey(at, "hosts"), j);
|
|
539
|
+
if (typeof h !== "string" || !own(HOSTS, h)) out.push(err2("unknown-host", hp, `${JSON.stringify(h)} is not a host; a view opens in "patter" or "storylets"`));
|
|
540
|
+
else if (!targeted.includes(h)) out.push({ severity: "warning", code: "view-host-untargeted", path: hp, message: `the view opens in ${h}, but the manifest targets nothing there` });
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
function readsProblems(reads, self, out) {
|
|
545
|
+
if (reads === void 0) return;
|
|
546
|
+
if (!Array.isArray(reads)) {
|
|
547
|
+
out.push(err2("not-a-list", "reads", "reads is a list of extension ids"));
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
const seen = /* @__PURE__ */ new Set();
|
|
551
|
+
reads.forEach((r, i) => {
|
|
552
|
+
const at = atIndex("reads", i);
|
|
553
|
+
if (typeof r !== "string" || !ID.test(r)) out.push(err2("reads-id", at, "an extension read is named by its id: lower case letters, digits and hyphens"));
|
|
554
|
+
else if (r === self) out.push({ severity: "warning", code: "reads-self", path: at, message: "an extension always reads its own data; this entry is ignored" });
|
|
555
|
+
else if (seen.has(r)) out.push(err2("reads-duplicate", at, `"${r}" is listed twice`));
|
|
556
|
+
else seen.add(r);
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
function viewsFor(manifest, host) {
|
|
560
|
+
const targeted = Object.keys(manifest.targets ?? {});
|
|
561
|
+
return (Array.isArray(manifest.views) ? manifest.views : []).filter((v) => isObject(v) && typeof v.id === "string" && ID.test(v.id) && typeof v.name === "string" && isViewEntry(v.entry) && typeof v.element === "string" && ELEMENT.test(v.element) && (v.hosts === void 0 ? targeted.includes(host) : Array.isArray(v.hosts) && v.hosts.includes(host)));
|
|
562
|
+
}
|
|
493
563
|
function unknownKeys(obj, known, path, out) {
|
|
494
564
|
for (const k of Object.keys(obj)) {
|
|
495
565
|
if (!known.has(k)) {
|
|
@@ -1146,6 +1216,7 @@ exports.effectiveClaim = effectiveClaim;
|
|
|
1146
1216
|
exports.entryProblems = entryProblems;
|
|
1147
1217
|
exports.extensionDataStrategy = extensionDataStrategy;
|
|
1148
1218
|
exports.isTextList = isTextList;
|
|
1219
|
+
exports.isViewEntry = isViewEntry;
|
|
1149
1220
|
exports.keyedBy = keyedBy;
|
|
1150
1221
|
exports.manifestProblems = manifestProblems;
|
|
1151
1222
|
exports.mapOf = mapOf;
|
|
@@ -1169,6 +1240,7 @@ exports.targetOf = targetOf;
|
|
|
1169
1240
|
exports.unresolvedOf = unresolvedOf;
|
|
1170
1241
|
exports.unresolvedProblems = unresolvedProblems;
|
|
1171
1242
|
exports.valueProblems = valueProblems;
|
|
1243
|
+
exports.viewsFor = viewsFor;
|
|
1172
1244
|
exports.withoutMark = withoutMark;
|
|
1173
1245
|
//# sourceMappingURL=extensions.cjs.map
|
|
1174
1246
|
//# sourceMappingURL=extensions.cjs.map
|