@wildwinter/toolkit 0.3.0 → 0.3.1
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 +12 -0
- package/conformance/extensions/manifest.json +275 -0
- package/dist/extensions.cjs +56 -2
- package/dist/extensions.cjs.map +1 -1
- package/dist/extensions.d.cts +9 -1
- package/dist/extensions.d.ts +9 -1
- package/dist/extensions.js +56 -3
- package/dist/extensions.js.map +1 -1
- package/extensions.md +17 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @wildwinter/toolkit
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Requirements in a manifest** (`./extensions`): `requires` names the other extensions, by id, that a project must
|
|
8
|
+
take for this one to work. The manifest check holds it to ids, each once, never the extension's own.
|
|
9
|
+
`missingRequirements(manifest, taken)` lists those a project lacks, for a host's Add Extension, its validation,
|
|
10
|
+
and its views.
|
|
11
|
+
- **A view as a field's editor** (`./extensions`): a target's own map of records can name one of the manifest's views
|
|
12
|
+
as its `editor`, which a host opens in place of its own record grid. The check holds it to a declared view that
|
|
13
|
+
opens in that host, and warns of one on any other kind of field, where it means nothing.
|
|
14
|
+
|
|
3
15
|
## 0.3.0
|
|
4
16
|
|
|
5
17
|
### Removed
|
|
@@ -1619,6 +1619,281 @@
|
|
|
1619
1619
|
"severity": "warning"
|
|
1620
1620
|
}
|
|
1621
1621
|
]
|
|
1622
|
+
},
|
|
1623
|
+
{
|
|
1624
|
+
"name": "requires and a field's editor pass",
|
|
1625
|
+
"manifest": {
|
|
1626
|
+
"schema": "wildwinter/extension@0",
|
|
1627
|
+
"id": "probe",
|
|
1628
|
+
"name": "Probe",
|
|
1629
|
+
"version": "1.0.0",
|
|
1630
|
+
"targets": {
|
|
1631
|
+
"patter": {
|
|
1632
|
+
"line": {
|
|
1633
|
+
"fields": [
|
|
1634
|
+
{
|
|
1635
|
+
"name": "performance",
|
|
1636
|
+
"type": "map",
|
|
1637
|
+
"key": {
|
|
1638
|
+
"type": "text"
|
|
1639
|
+
},
|
|
1640
|
+
"of": {
|
|
1641
|
+
"type": "record",
|
|
1642
|
+
"fields": [
|
|
1643
|
+
{
|
|
1644
|
+
"name": "look",
|
|
1645
|
+
"type": "text"
|
|
1646
|
+
}
|
|
1647
|
+
]
|
|
1648
|
+
},
|
|
1649
|
+
"editor": "sheet"
|
|
1650
|
+
}
|
|
1651
|
+
]
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
},
|
|
1655
|
+
"views": [
|
|
1656
|
+
{
|
|
1657
|
+
"id": "sheet",
|
|
1658
|
+
"name": "Sheet",
|
|
1659
|
+
"entry": "view/sheet.js",
|
|
1660
|
+
"element": "probe-sheet",
|
|
1661
|
+
"hosts": [
|
|
1662
|
+
"patter"
|
|
1663
|
+
]
|
|
1664
|
+
}
|
|
1665
|
+
],
|
|
1666
|
+
"reads": [
|
|
1667
|
+
"patterstage"
|
|
1668
|
+
],
|
|
1669
|
+
"requires": [
|
|
1670
|
+
"patterstage"
|
|
1671
|
+
]
|
|
1672
|
+
},
|
|
1673
|
+
"problems": []
|
|
1674
|
+
},
|
|
1675
|
+
{
|
|
1676
|
+
"name": "requires names other extensions, once each",
|
|
1677
|
+
"manifest": {
|
|
1678
|
+
"schema": "wildwinter/extension@0",
|
|
1679
|
+
"id": "probe",
|
|
1680
|
+
"name": "Probe",
|
|
1681
|
+
"version": "1.0.0",
|
|
1682
|
+
"targets": {
|
|
1683
|
+
"patter": {
|
|
1684
|
+
"line": {
|
|
1685
|
+
"fields": [
|
|
1686
|
+
{
|
|
1687
|
+
"name": "mood",
|
|
1688
|
+
"type": "text"
|
|
1689
|
+
}
|
|
1690
|
+
]
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
},
|
|
1694
|
+
"requires": [
|
|
1695
|
+
"patterstage",
|
|
1696
|
+
"probe",
|
|
1697
|
+
"patterstage",
|
|
1698
|
+
"Bad"
|
|
1699
|
+
]
|
|
1700
|
+
},
|
|
1701
|
+
"problems": [
|
|
1702
|
+
{
|
|
1703
|
+
"path": "requires[1]",
|
|
1704
|
+
"code": "requires-self"
|
|
1705
|
+
},
|
|
1706
|
+
{
|
|
1707
|
+
"path": "requires[2]",
|
|
1708
|
+
"code": "requires-duplicate"
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
"path": "requires[3]",
|
|
1712
|
+
"code": "requires-id"
|
|
1713
|
+
}
|
|
1714
|
+
]
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
"name": "requires must be a list",
|
|
1718
|
+
"manifest": {
|
|
1719
|
+
"schema": "wildwinter/extension@0",
|
|
1720
|
+
"id": "probe",
|
|
1721
|
+
"name": "Probe",
|
|
1722
|
+
"version": "1.0.0",
|
|
1723
|
+
"targets": {
|
|
1724
|
+
"patter": {
|
|
1725
|
+
"line": {
|
|
1726
|
+
"fields": [
|
|
1727
|
+
{
|
|
1728
|
+
"name": "mood",
|
|
1729
|
+
"type": "text"
|
|
1730
|
+
}
|
|
1731
|
+
]
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
},
|
|
1735
|
+
"requires": "patterstage"
|
|
1736
|
+
},
|
|
1737
|
+
"problems": [
|
|
1738
|
+
{
|
|
1739
|
+
"path": "requires",
|
|
1740
|
+
"code": "not-a-list"
|
|
1741
|
+
}
|
|
1742
|
+
]
|
|
1743
|
+
},
|
|
1744
|
+
{
|
|
1745
|
+
"name": "a field's editor names a view that opens in its host, on a map of records",
|
|
1746
|
+
"manifest": {
|
|
1747
|
+
"schema": "wildwinter/extension@0",
|
|
1748
|
+
"id": "probe",
|
|
1749
|
+
"name": "Probe",
|
|
1750
|
+
"version": "1.0.0",
|
|
1751
|
+
"targets": {
|
|
1752
|
+
"patter": {
|
|
1753
|
+
"line": {
|
|
1754
|
+
"fields": [
|
|
1755
|
+
{
|
|
1756
|
+
"name": "perf",
|
|
1757
|
+
"type": "map",
|
|
1758
|
+
"key": {
|
|
1759
|
+
"type": "text"
|
|
1760
|
+
},
|
|
1761
|
+
"of": {
|
|
1762
|
+
"type": "record",
|
|
1763
|
+
"fields": [
|
|
1764
|
+
{
|
|
1765
|
+
"name": "look",
|
|
1766
|
+
"type": "text",
|
|
1767
|
+
"editor": "sheet"
|
|
1768
|
+
}
|
|
1769
|
+
]
|
|
1770
|
+
},
|
|
1771
|
+
"editor": "nope"
|
|
1772
|
+
},
|
|
1773
|
+
{
|
|
1774
|
+
"name": "cues",
|
|
1775
|
+
"type": "map",
|
|
1776
|
+
"key": {
|
|
1777
|
+
"type": "text"
|
|
1778
|
+
},
|
|
1779
|
+
"of": {
|
|
1780
|
+
"type": "record",
|
|
1781
|
+
"fields": [
|
|
1782
|
+
{
|
|
1783
|
+
"name": "at",
|
|
1784
|
+
"type": "number"
|
|
1785
|
+
}
|
|
1786
|
+
]
|
|
1787
|
+
},
|
|
1788
|
+
"editor": 3
|
|
1789
|
+
},
|
|
1790
|
+
{
|
|
1791
|
+
"name": "mood",
|
|
1792
|
+
"type": "text",
|
|
1793
|
+
"editor": "sheet"
|
|
1794
|
+
}
|
|
1795
|
+
]
|
|
1796
|
+
}
|
|
1797
|
+
},
|
|
1798
|
+
"storylets": {
|
|
1799
|
+
"card": {
|
|
1800
|
+
"fields": [
|
|
1801
|
+
{
|
|
1802
|
+
"name": "perf",
|
|
1803
|
+
"type": "map",
|
|
1804
|
+
"key": {
|
|
1805
|
+
"type": "text"
|
|
1806
|
+
},
|
|
1807
|
+
"of": {
|
|
1808
|
+
"type": "record",
|
|
1809
|
+
"fields": [
|
|
1810
|
+
{
|
|
1811
|
+
"name": "look",
|
|
1812
|
+
"type": "text"
|
|
1813
|
+
}
|
|
1814
|
+
]
|
|
1815
|
+
},
|
|
1816
|
+
"editor": "sheet"
|
|
1817
|
+
}
|
|
1818
|
+
]
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
},
|
|
1822
|
+
"views": [
|
|
1823
|
+
{
|
|
1824
|
+
"id": "sheet",
|
|
1825
|
+
"name": "Sheet",
|
|
1826
|
+
"entry": "view/sheet.js",
|
|
1827
|
+
"element": "probe-sheet",
|
|
1828
|
+
"hosts": [
|
|
1829
|
+
"patter"
|
|
1830
|
+
]
|
|
1831
|
+
}
|
|
1832
|
+
]
|
|
1833
|
+
},
|
|
1834
|
+
"problems": [
|
|
1835
|
+
{
|
|
1836
|
+
"path": "targets.patter.line.fields[0].of.fields[0].editor",
|
|
1837
|
+
"code": "editor-nested"
|
|
1838
|
+
},
|
|
1839
|
+
{
|
|
1840
|
+
"path": "targets.patter.line.fields[0].editor",
|
|
1841
|
+
"code": "editor-view"
|
|
1842
|
+
},
|
|
1843
|
+
{
|
|
1844
|
+
"path": "targets.patter.line.fields[1].editor",
|
|
1845
|
+
"code": "editor-view"
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
"path": "targets.patter.line.fields[2].editor",
|
|
1849
|
+
"code": "editor-ignored",
|
|
1850
|
+
"severity": "warning"
|
|
1851
|
+
},
|
|
1852
|
+
{
|
|
1853
|
+
"path": "targets.storylets.card.fields[0].editor",
|
|
1854
|
+
"code": "editor-host"
|
|
1855
|
+
}
|
|
1856
|
+
]
|
|
1857
|
+
},
|
|
1858
|
+
{
|
|
1859
|
+
"name": "an editor names a view the manifest declares",
|
|
1860
|
+
"manifest": {
|
|
1861
|
+
"schema": "wildwinter/extension@0",
|
|
1862
|
+
"id": "probe",
|
|
1863
|
+
"name": "Probe",
|
|
1864
|
+
"version": "1.0.0",
|
|
1865
|
+
"targets": {
|
|
1866
|
+
"patter": {
|
|
1867
|
+
"line": {
|
|
1868
|
+
"fields": [
|
|
1869
|
+
{
|
|
1870
|
+
"name": "perf",
|
|
1871
|
+
"type": "map",
|
|
1872
|
+
"key": {
|
|
1873
|
+
"type": "text"
|
|
1874
|
+
},
|
|
1875
|
+
"of": {
|
|
1876
|
+
"type": "record",
|
|
1877
|
+
"fields": [
|
|
1878
|
+
{
|
|
1879
|
+
"name": "look",
|
|
1880
|
+
"type": "text"
|
|
1881
|
+
}
|
|
1882
|
+
]
|
|
1883
|
+
},
|
|
1884
|
+
"editor": "sheet"
|
|
1885
|
+
}
|
|
1886
|
+
]
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
},
|
|
1891
|
+
"problems": [
|
|
1892
|
+
{
|
|
1893
|
+
"path": "targets.patter.line.fields[0].editor",
|
|
1894
|
+
"code": "editor-view"
|
|
1895
|
+
}
|
|
1896
|
+
]
|
|
1622
1897
|
}
|
|
1623
1898
|
]
|
|
1624
1899
|
}
|
package/dist/extensions.cjs
CHANGED
|
@@ -365,9 +365,9 @@ var ID = /^[a-z][a-z0-9-]*$/;
|
|
|
365
365
|
var VERSION = /^\d+\.\d+\.\d+$/;
|
|
366
366
|
var NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
367
367
|
var TYPE_KEYS = ["type", "values", "stages", "renamedStages", "to", "from", "fields", "key", "of", "id", "min", "max", "valueHelp", "default"];
|
|
368
|
-
var FIELD_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "name", "label", "help", "required", "group", "editorOnly"]);
|
|
368
|
+
var FIELD_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "name", "label", "help", "required", "group", "editorOnly", "editor"]);
|
|
369
369
|
var BARE_KEYS = new Set(TYPE_KEYS);
|
|
370
|
-
var MANIFEST_KEYS = /* @__PURE__ */ new Set(["schema", "id", "name", "version", "docs", "targets", "views", "reads"]);
|
|
370
|
+
var MANIFEST_KEYS = /* @__PURE__ */ new Set(["schema", "id", "name", "version", "docs", "targets", "views", "reads", "requires"]);
|
|
371
371
|
var REMOVED_MANIFEST_KEYS = {
|
|
372
372
|
settings: "settings were removed with claims; declare the extension's own fields, or a project field for a project-wide value"
|
|
373
373
|
};
|
|
@@ -398,6 +398,7 @@ function manifestProblems(manifest) {
|
|
|
398
398
|
if (m["docs"] !== void 0 && typeof m["docs"] !== "string") out.push(err2("docs", "docs", "docs is a link, as text"));
|
|
399
399
|
viewsProblems(m["views"], m["targets"], out);
|
|
400
400
|
readsProblems(m["reads"], m["id"], out);
|
|
401
|
+
requiresProblems(m["requires"], m["id"], out);
|
|
401
402
|
const targets = m["targets"];
|
|
402
403
|
if (!isObject(targets) || Object.keys(targets).length === 0) {
|
|
403
404
|
out.push(err2("no-targets", "targets", "the manifest targets no host"));
|
|
@@ -423,6 +424,7 @@ function manifestProblems(manifest) {
|
|
|
423
424
|
targetProblems(host, target, kindPath, out);
|
|
424
425
|
}
|
|
425
426
|
pickListProblems(kinds, hostPath, out);
|
|
427
|
+
editorProblems(host, kinds, m["views"], Object.keys(targets), hostPath, out);
|
|
426
428
|
}
|
|
427
429
|
return out;
|
|
428
430
|
}
|
|
@@ -562,6 +564,54 @@ function readsProblems(reads, self, out) {
|
|
|
562
564
|
else seen.add(r);
|
|
563
565
|
});
|
|
564
566
|
}
|
|
567
|
+
function requiresProblems(requires, self, out) {
|
|
568
|
+
if (requires === void 0) return;
|
|
569
|
+
if (!Array.isArray(requires)) {
|
|
570
|
+
out.push(err2("not-a-list", "requires", "requires is a list of extension ids"));
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
const seen = /* @__PURE__ */ new Set();
|
|
574
|
+
requires.forEach((r, i) => {
|
|
575
|
+
const at = atIndex("requires", i);
|
|
576
|
+
if (typeof r !== "string" || !ID.test(r)) out.push(err2("requires-id", at, "a required extension is named by its id: lower case letters, digits and hyphens"));
|
|
577
|
+
else if (r === self) out.push(err2("requires-self", at, "an extension can't require itself"));
|
|
578
|
+
else if (seen.has(r)) out.push(err2("requires-duplicate", at, `"${r}" is listed twice`));
|
|
579
|
+
else seen.add(r);
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
function missingRequirements(manifest, taken) {
|
|
583
|
+
const have = new Set(taken);
|
|
584
|
+
const out = [];
|
|
585
|
+
for (const r of Array.isArray(manifest.requires) ? manifest.requires : []) {
|
|
586
|
+
if (typeof r === "string" && ID.test(r) && r !== manifest.id && !have.has(r) && !out.includes(r)) out.push(r);
|
|
587
|
+
}
|
|
588
|
+
return out;
|
|
589
|
+
}
|
|
590
|
+
function editorProblems(host, kinds, views, targeted, hostPath, out) {
|
|
591
|
+
const declared = Array.isArray(views) ? views.filter((v) => isObject(v) && typeof v["id"] === "string") : [];
|
|
592
|
+
for (const [kind, target] of Object.entries(kinds)) {
|
|
593
|
+
if (!isObject(target) || !Array.isArray(target["fields"])) continue;
|
|
594
|
+
target["fields"].forEach((f, i) => {
|
|
595
|
+
if (!isObject(f) || f["editor"] === void 0) return;
|
|
596
|
+
const at = atKey(atIndex(atKey(atKey(hostPath, kind), "fields"), i), "editor");
|
|
597
|
+
const editor = f["editor"];
|
|
598
|
+
const view = typeof editor === "string" ? declared.find((v) => v["id"] === editor) : void 0;
|
|
599
|
+
if (view === void 0) {
|
|
600
|
+
out.push(err2("editor-view", at, typeof editor === "string" ? `the manifest declares no view called "${editor}"; an editor names one of its views by id` : "an editor names one of the manifest's views by its id"));
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
const opensIn = Array.isArray(view["hosts"]) ? view["hosts"] : targeted;
|
|
604
|
+
if (!opensIn.includes(host)) {
|
|
605
|
+
out.push(err2("editor-host", at, `the view "${editor}" doesn't open in ${host}`));
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
const d = f;
|
|
609
|
+
if (!(d.type === "map" && isObject(d.of) && d.of.type === "record")) {
|
|
610
|
+
out.push({ severity: "warning", code: "editor-ignored", path: at, message: "only a map of records opens in an editor; this field is edited in place, so the editor is ignored" });
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
}
|
|
565
615
|
function viewsFor(manifest, host) {
|
|
566
616
|
const targeted = Object.keys(manifest.targets ?? {});
|
|
567
617
|
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)));
|
|
@@ -609,6 +659,9 @@ function fieldListProblems(host, fields, path, topLevel, out) {
|
|
|
609
659
|
if (field.editorOnly !== void 0 && !topLevel) {
|
|
610
660
|
out.push(err2("editor-only-nested", atKey(at, "editorOnly"), "only a target's own fields can be editor-only, not a record's"));
|
|
611
661
|
}
|
|
662
|
+
if (field.editor !== void 0 && !topLevel) {
|
|
663
|
+
out.push(err2("editor-nested", atKey(at, "editor"), "only a target's own fields open in a view, not a record's"));
|
|
664
|
+
}
|
|
612
665
|
for (const flag of ["required", "editorOnly"]) {
|
|
613
666
|
if (field[flag] !== void 0 && typeof field[flag] !== "boolean") {
|
|
614
667
|
out.push(err2("not-a-boolean", atKey(at, flag), `${flag} is true or false`));
|
|
@@ -1120,6 +1173,7 @@ exports.markUnresolved = markUnresolved;
|
|
|
1120
1173
|
exports.mergeComments = mergeComments;
|
|
1121
1174
|
exports.mergeExtensionData = mergeExtensionData;
|
|
1122
1175
|
exports.mergeTree = mergeTree;
|
|
1176
|
+
exports.missingRequirements = missingRequirements;
|
|
1123
1177
|
exports.objectOf = objectOf;
|
|
1124
1178
|
exports.orphanedEntries = orphanedEntries;
|
|
1125
1179
|
exports.parseManifest = parseManifest;
|