andesine 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/cli.js +39 -80
- package/dist/cli.js.map +1 -1
- package/dist/templates/extension/README.md +11 -5
- package/dist/templates/extension/andesine.config.ts +21 -17
- package/dist/templates/extension/package.template.json +4 -4
- package/dist/templates/extension/src/backend/server.ts +0 -5
- package/dist/templates/extension/src/frontend/count-words-action.tsx +46 -0
- package/dist/templates/extension/src/frontend/hello-panel.tsx +35 -3
- package/dist/templates/extension/src/frontend/index.tsx +2 -2
- package/dist/templates/extension/src/frontend/note-view.tsx +1 -4
- package/dist/templates/extension/src/frontend/shout-action.tsx +18 -42
- package/dist/templates/extension/src/frontend/wrap-in-note-action.tsx +52 -0
- package/dist/templates/pages/package.template.json +3 -3
- package/dist/templates/pages/src/components/content/copy-button.tsx +1 -1
- package/dist/templates/pages/src/components/layout/call-to-action.tsx +2 -6
- package/dist/templates/pages/src/components/layout/footer.astro +1 -2
- package/dist/templates/pages/src/components/layout/header.astro +0 -3
- package/dist/templates/pages/src/components/layout/mobile-navigation.tsx +1 -1
- package/dist/templates/pages/src/components/layout/page-actions.tsx +1 -7
- package/dist/templates/pages/src/components/primitives/button.tsx +21 -37
- package/dist/templates/pages/src/components/search/search-palette.tsx +1 -3
- package/package.json +4 -4
- package/dist/templates/extension/src/frontend/about-section.tsx +0 -47
- package/dist/templates/extension/src/frontend/bookmarks-panel.tsx +0 -67
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
- Validate extension manifests with the 0.6.0 rules: `settingsSections` is no longer
|
|
6
|
+
accepted, and element views accept a `description` and an `icon`, whose CSS
|
|
7
|
+
`extensions build` generates with the other manifest icons.
|
|
8
|
+
- Update the `extensions init` template: block action samples without UI (“Shout”), with a
|
|
9
|
+
`Menu` (“Count words”), and with a `Dialog` (“Wrap in Note”); a “More” menu and an “About”
|
|
10
|
+
dialog in the panel sample; a description and an icon for the Note view; and a local setup
|
|
11
|
+
guide in its README. The bookmarks panel and the About settings section samples, and the
|
|
12
|
+
declared request URL, are removed.
|
|
13
|
+
- Simplify the buttons of the `pages init` template: one `variant` (`primary`, `secondary`, or
|
|
14
|
+
`ghost`) replaces `variant` and `color`, and buttons default to the small size.
|
|
15
|
+
|
|
3
16
|
## 0.5.0
|
|
4
17
|
|
|
5
18
|
- Accept the `extensions` role permission (manage workspace extensions) in role commands.
|
package/dist/cli.js
CHANGED
|
@@ -51,7 +51,7 @@ var CancelledError = class extends CLIError {
|
|
|
51
51
|
};
|
|
52
52
|
//#endregion
|
|
53
53
|
//#region package.json
|
|
54
|
-
var version = "0.
|
|
54
|
+
var version = "0.6.0";
|
|
55
55
|
//#endregion
|
|
56
56
|
//#region src/config/files.ts
|
|
57
57
|
/** Read declarative JSON only. Missing optional files are distinct from invalid files. */
|
|
@@ -1896,10 +1896,7 @@ const isEmptyDirectory = async (directory) => {
|
|
|
1896
1896
|
const toPackageName = (directory, fallback) => {
|
|
1897
1897
|
return path.basename(directory).toLowerCase().replace(/[^a-z\d._~-]+/g, "-").replace(/^[._-]+|[-]+$/g, "") || fallback;
|
|
1898
1898
|
};
|
|
1899
|
-
/**
|
|
1900
|
-
* Copies a template that the build places next to the bundled CLI (see `scripts/templates.ts`)
|
|
1901
|
-
* into a new or empty directory, named after the directory.
|
|
1902
|
-
*/
|
|
1899
|
+
/** Copies a bundled template (see `scripts/templates.ts`) into a new or empty directory. */
|
|
1903
1900
|
const copyTemplate = async (template, directory, output) => {
|
|
1904
1901
|
const source = fileURLToPath(new URL(`./templates/${template}/`, import.meta.url));
|
|
1905
1902
|
const target = path.resolve(directory);
|
|
@@ -9067,7 +9064,6 @@ const publicID = (prefix, options) => {
|
|
|
9067
9064
|
};
|
|
9068
9065
|
//#endregion
|
|
9069
9066
|
//#region ../../private/contracts/src/primitives/unique.ts
|
|
9070
|
-
/** Whether every value is distinct. */
|
|
9071
9067
|
const uniqueItems = (values) => new Set(values).size === values.length;
|
|
9072
9068
|
//#endregion
|
|
9073
9069
|
//#region ../../private/contracts/src/webhooks/catalog-definitions.ts
|
|
@@ -9499,7 +9495,7 @@ const fieldType = z.union([
|
|
|
9499
9495
|
])).optional()
|
|
9500
9496
|
})
|
|
9501
9497
|
]);
|
|
9502
|
-
/** Flat JSON Schema
|
|
9498
|
+
/** Flat JSON Schema 2020-12 subset; the host validates it without running extension code. */
|
|
9503
9499
|
const extensionConfigurationType = z.strictObject({
|
|
9504
9500
|
$schema: z.literal(JSON_SCHEMA_DIALECT).optional(),
|
|
9505
9501
|
type: z.literal("object"),
|
|
@@ -9800,27 +9796,22 @@ const contentNodeType = z.lazy(() => {
|
|
|
9800
9796
|
const extensionContributionLimits = {
|
|
9801
9797
|
elementViews: 50,
|
|
9802
9798
|
blockActions: 20,
|
|
9803
|
-
panelsPerSide: 2
|
|
9804
|
-
settingsSections: 5
|
|
9799
|
+
panelsPerSide: 2
|
|
9805
9800
|
};
|
|
9806
9801
|
/** Stable across versions; settings and managed records are keyed by it. */
|
|
9807
9802
|
const extensionStableIDType = z.string().regex(/^[A-Za-z][A-Za-z0-9_-]{0,63}$/, "Use a letter, then letters, digits, - or _");
|
|
9808
9803
|
const extensionEntryType = z.string().regex(/^[A-Za-z_$][A-Za-z0-9_$]{0,63}$/, "Use the name of an exported view").describe("The export of the frontend bundle that renders this contribution");
|
|
9809
|
-
/**
|
|
9810
|
-
* An icon class of the UnoCSS icons preset, e.g. `i-lucide:rocket`, or `i-acme:logo?bg` for a
|
|
9811
|
-
* colored icon. Sets come from the extension build (default, installed, or custom); the build
|
|
9812
|
-
* checks that each icon exists.
|
|
9813
|
-
*/
|
|
9804
|
+
/** UnoCSS icon class, e.g. `i-lucide:rocket` (`?bg` for colored); the build checks it exists. */
|
|
9814
9805
|
const extensionIconType = z.string().max(120).regex(/^i-[a-z\d]+(?:-[a-z\d]+)*:[a-z\d]+(?:-[a-z\d]+)*(?:\?(?:bg|mask))?$/, "Use an icon class, e.g. i-lucide:rocket");
|
|
9815
9806
|
const labelType = z.string().min(1).max(60);
|
|
9816
9807
|
const elementNameType = z.string().max(100).regex(ELEMENT_TAG_NAME, "Use an element name, e.g. Accordion");
|
|
9817
|
-
/**
|
|
9818
|
-
* A root element view. `descendants` render elements of those names inside the root's content
|
|
9819
|
-
* (nearest root first), before their own root registrations.
|
|
9820
|
-
*/
|
|
9808
|
+
/** `descendants` override their elements' own root views inside this root (nearest root first). */
|
|
9821
9809
|
const extensionElementViewType = z.strictObject({
|
|
9822
9810
|
id: extensionStableIDType,
|
|
9823
9811
|
name: labelType,
|
|
9812
|
+
/** Shown in the editor's slash menu and the extension's settings. */
|
|
9813
|
+
description: z.string().min(1).max(200).optional(),
|
|
9814
|
+
icon: extensionIconType.optional(),
|
|
9824
9815
|
element: elementNameType,
|
|
9825
9816
|
entry: extensionEntryType,
|
|
9826
9817
|
descendants: z.array(z.strictObject({
|
|
@@ -9854,11 +9845,6 @@ const extensionPanelType = z.discriminatedUnion("side", [z.strictObject({
|
|
|
9854
9845
|
]),
|
|
9855
9846
|
entry: extensionEntryType
|
|
9856
9847
|
})]);
|
|
9857
|
-
const extensionSettingsSectionType = z.strictObject({
|
|
9858
|
-
id: extensionStableIDType,
|
|
9859
|
-
heading: labelType,
|
|
9860
|
-
entry: extensionEntryType
|
|
9861
|
-
});
|
|
9862
9848
|
const extensionContributionsType = {
|
|
9863
9849
|
elementViews: z.array(extensionElementViewType).max(extensionContributionLimits.elementViews).refine((views) => uniqueItems(views.map(({ element }) => element.toLowerCase())), "Use one view per element").default([]),
|
|
9864
9850
|
blockActions: z.array(extensionBlockActionType).max(extensionContributionLimits.blockActions).default([]),
|
|
@@ -9866,8 +9852,7 @@ const extensionContributionsType = {
|
|
|
9866
9852
|
return ["left", "right"].every((side) => {
|
|
9867
9853
|
return panels.filter((panel) => panel.side === side).length <= extensionContributionLimits.panelsPerSide;
|
|
9868
9854
|
});
|
|
9869
|
-
}, `Use at most ${extensionContributionLimits.panelsPerSide} panels per side`).default([])
|
|
9870
|
-
settingsSections: z.array(extensionSettingsSectionType).max(extensionContributionLimits.settingsSections).default([])
|
|
9855
|
+
}, `Use at most ${extensionContributionLimits.panelsPerSide} panels per side`).default([])
|
|
9871
9856
|
};
|
|
9872
9857
|
//#endregion
|
|
9873
9858
|
//#region ../../private/contracts/src/api/schemas/webhooks.ts
|
|
@@ -10074,8 +10059,7 @@ const createManifestType = (protocols) => {
|
|
|
10074
10059
|
const contributionIDs = [
|
|
10075
10060
|
...manifest.elementViews,
|
|
10076
10061
|
...manifest.blockActions,
|
|
10077
|
-
...manifest.panels
|
|
10078
|
-
...manifest.settingsSections
|
|
10062
|
+
...manifest.panels
|
|
10079
10063
|
].map(({ id }) => id);
|
|
10080
10064
|
const isGranted = (required) => {
|
|
10081
10065
|
return manifest.permissions.some((permission) => hasPermission(permission, required));
|
|
@@ -10216,8 +10200,7 @@ const getEntries = (manifest) => {
|
|
|
10216
10200
|
const entries = [
|
|
10217
10201
|
...manifest.elementViews.flatMap((view) => [view.entry, ...view.descendants.map(({ entry }) => entry)]),
|
|
10218
10202
|
...manifest.blockActions.map(({ entry }) => entry),
|
|
10219
|
-
...manifest.panels.map(({ entry }) => entry)
|
|
10220
|
-
...manifest.settingsSections.map(({ entry }) => entry)
|
|
10203
|
+
...manifest.panels.map(({ entry }) => entry)
|
|
10221
10204
|
];
|
|
10222
10205
|
return [...new Set(entries)];
|
|
10223
10206
|
};
|
|
@@ -10325,10 +10308,7 @@ const importConfig = async (root) => {
|
|
|
10325
10308
|
});
|
|
10326
10309
|
return import(`${pathToFileURL(file).href}?t=${Date.now()}`);
|
|
10327
10310
|
};
|
|
10328
|
-
/**
|
|
10329
|
-
* Loads and validates the manifest and build options of the extension in `root`. In
|
|
10330
|
-
* development, the manifest's backend uses the development keys and URL, and may use local HTTP.
|
|
10331
|
-
*/
|
|
10311
|
+
/** Loads and validates the project; in development, the backend uses dev keys and may use HTTP. */
|
|
10332
10312
|
const loadExtensionProject = async (root, development) => {
|
|
10333
10313
|
if (!await exists(path.join(root, CONFIG_FILE))) throw new CLIError(`No ${CONFIG_FILE} in ${root}.`, exitCodes.usage);
|
|
10334
10314
|
const config = await importConfig(root);
|
|
@@ -10382,10 +10362,7 @@ const getViewScopePrelude = (name) => {
|
|
|
10382
10362
|
const fail = (message) => {
|
|
10383
10363
|
throw new ExtensionStyleError(message);
|
|
10384
10364
|
};
|
|
10385
|
-
/**
|
|
10386
|
-
* Removes comments outside strings. Escapes and strings are read like the browser reads them,
|
|
10387
|
-
* and a raw newline in a string fails, so the validated text cannot differ from what applies.
|
|
10388
|
-
*/
|
|
10365
|
+
/** Strips comments, parsing like the browser so the validated text matches what applies. */
|
|
10389
10366
|
const stripComments = (css) => {
|
|
10390
10367
|
let result = "";
|
|
10391
10368
|
let quote = "";
|
|
@@ -10450,10 +10427,11 @@ const splitSelectors = (prelude) => {
|
|
|
10450
10427
|
selectors.push(prelude.slice(start).trim());
|
|
10451
10428
|
return selectors;
|
|
10452
10429
|
};
|
|
10453
|
-
/**
|
|
10430
|
+
/** Each selector descends from `prefix` (no bare prefix); sibling combinators escape the scope. */
|
|
10454
10431
|
const isScopedSelectorList = (selectors, prefix) => {
|
|
10455
10432
|
return splitSelectors(selectors).every((selector) => {
|
|
10456
|
-
|
|
10433
|
+
const rest = selector.slice(prefix.length).trim();
|
|
10434
|
+
return selector.startsWith(`${prefix} `) && rest.length > 0 && !/^[~+]/.test(rest);
|
|
10457
10435
|
});
|
|
10458
10436
|
};
|
|
10459
10437
|
/** Values load nothing (only inline SVG icon URLs) and contain no escapes or nested blocks. */
|
|
@@ -10489,10 +10467,8 @@ const validateBlock = (css, start, end, prefix, scopePrelude) => {
|
|
|
10489
10467
|
}
|
|
10490
10468
|
};
|
|
10491
10469
|
/**
|
|
10492
|
-
* View CSS is one `@scope (<view>) to (<content slot>)` rule
|
|
10493
|
-
*
|
|
10494
|
-
* (optionally in `@media`/`@supports`) without escapes in values or URL-bearing values other
|
|
10495
|
-
* than inline SVG icons. The host also checks the browser-parsed rules before applying them.
|
|
10470
|
+
* View CSS is one `@scope (<view>) to (<content slot>)` rule; icon CSS starts with the icon scope.
|
|
10471
|
+
* Inside, only style rules (or `@media`/`@supports`) with safe values; the host re-checks them.
|
|
10496
10472
|
*/
|
|
10497
10473
|
const validateExtensionCSS = (css, name, kind = "view") => {
|
|
10498
10474
|
if (css.length > 262144) fail("Extension CSS is too large");
|
|
@@ -10567,10 +10543,8 @@ const createExtensionGenerator = (icons) => {
|
|
|
10567
10543
|
});
|
|
10568
10544
|
};
|
|
10569
10545
|
/**
|
|
10570
|
-
* Generates
|
|
10571
|
-
*
|
|
10572
|
-
* (the host has them). Throws if the result is invalid, for example when an arbitrary value
|
|
10573
|
-
* loads a URL.
|
|
10546
|
+
* Generates view CSS in one `@scope` rule from the views down to their content slots, without
|
|
10547
|
+
* preflights (the host has them). Throws if invalid, e.g. when an arbitrary value loads a URL.
|
|
10574
10548
|
*/
|
|
10575
10549
|
const generateExtensionCSS = async (options) => {
|
|
10576
10550
|
const { css: rules } = await (await createExtensionGenerator(options.icons)).generate(options.code, {
|
|
@@ -10620,7 +10594,8 @@ const getManifestIcons = (manifest) => {
|
|
|
10620
10594
|
const icons = [
|
|
10621
10595
|
manifest.icon,
|
|
10622
10596
|
...manifest.panels.map(({ icon }) => icon),
|
|
10623
|
-
...manifest.blockActions.map(({ icon }) => icon)
|
|
10597
|
+
...manifest.blockActions.map(({ icon }) => icon),
|
|
10598
|
+
...manifest.elementViews.map(({ icon }) => icon)
|
|
10624
10599
|
];
|
|
10625
10600
|
return [...new Set(icons.filter((icon) => icon !== void 0))];
|
|
10626
10601
|
};
|
|
@@ -10726,10 +10701,7 @@ const describeFailure = (status, body) => {
|
|
|
10726
10701
|
if (status === 404 && (body === null || message === "Not Found")) return "The instance has no development endpoints. Set PUBLIC_EXTENSIONS_ENABLED=true and EXTENSIONS_DEVELOPMENT_ENABLED=true on the local backend.";
|
|
10727
10702
|
return typeof message === "string" ? message : `The request failed (HTTP ${status}).`;
|
|
10728
10703
|
};
|
|
10729
|
-
/**
|
|
10730
|
-
* A client for the development operations of a local instance. They are not in the public API,
|
|
10731
|
-
* so the SDK has no methods for them; they need the signed-in member of a CLI profile.
|
|
10732
|
-
*/
|
|
10704
|
+
/** Client for the local instance's development endpoints, which are outside the public API. */
|
|
10733
10705
|
const createDevelopmentClient = (context) => {
|
|
10734
10706
|
const { baseURL, workspaceID } = context.config;
|
|
10735
10707
|
if (!isLocalInstance(baseURL)) throw new CLIError(`${baseURL} is not a local instance. Extension development needs a local stack (localhost, *.localhost, *.local, or *.test); use --base-url.`, exitCodes.usage);
|
|
@@ -10897,10 +10869,7 @@ const generateExtensionKey = async (root, options = {}) => {
|
|
|
10897
10869
|
ignored: await isIgnored$1(root, file)
|
|
10898
10870
|
};
|
|
10899
10871
|
};
|
|
10900
|
-
/**
|
|
10901
|
-
* Checks that a private key matches a current key of the manifest and, with a registry URL, of
|
|
10902
|
-
* the registry entry, which Andesine instances trust.
|
|
10903
|
-
*/
|
|
10872
|
+
/** Checks that a private key matches a current manifest key and, optionally, a registry key. */
|
|
10904
10873
|
const checkExtensionKey = async (root, options = {}) => {
|
|
10905
10874
|
const source = options.key ? await readFile(path.resolve(options.key), "utf8") : process.env[KEY_ENVIRONMENT_VARIABLE];
|
|
10906
10875
|
if (!source) throw new CLIError(`Set ${KEY_ENVIRONMENT_VARIABLE} or use --key <file>.`, exitCodes.usage);
|
|
@@ -10942,10 +10911,7 @@ const revokeExtensionKey = async (root, kid) => {
|
|
|
10942
10911
|
//#region src/extensions/dev/environment.ts
|
|
10943
10912
|
const KEY_ID = "development";
|
|
10944
10913
|
const INSTANCES_VARIABLE = "ANDESINE_INSTANCES";
|
|
10945
|
-
/**
|
|
10946
|
-
* The project's development key pair, created once. The local instance gets only the public
|
|
10947
|
-
* key; the private key stays in the work directory and the backend's environment file.
|
|
10948
|
-
*/
|
|
10914
|
+
/** The project's development key pair, created once; the instance gets only the public key. */
|
|
10949
10915
|
const getDevelopmentKey = async (root) => {
|
|
10950
10916
|
const directory = path.join(root, WORK_DIRECTORY, "keys");
|
|
10951
10917
|
const file = path.join(directory, `${KEY_ID}.json`);
|
|
@@ -10982,10 +10948,7 @@ const setVariable = (source, name, value) => {
|
|
|
10982
10948
|
if (pattern.test(source)) return source.replace(pattern, () => line);
|
|
10983
10949
|
return `${source}${source && !source.endsWith("\n") ? "\n" : ""}${line}\n`;
|
|
10984
10950
|
};
|
|
10985
|
-
/**
|
|
10986
|
-
* Points the local backend at the development key and trusts the local instance, in its
|
|
10987
|
-
* environment file (created from `.env.example` when missing). Other variables stay.
|
|
10988
|
-
*/
|
|
10951
|
+
/** Sets the development key and trusted instance in the backend's environment file. */
|
|
10989
10952
|
const writeDevelopmentEnvironment = async (root, file, key, baseURL) => {
|
|
10990
10953
|
const target = path.resolve(root, file);
|
|
10991
10954
|
const example = path.join(root, ".env.example");
|
|
@@ -11046,9 +11009,12 @@ const STOP_TIMEOUT = 1e4;
|
|
|
11046
11009
|
const disabledHints = {
|
|
11047
11010
|
approval_required: "approve its new permissions or URLs in Settings → Extensions",
|
|
11048
11011
|
configuration_required: "fill in its required configuration in Settings → Extensions",
|
|
11049
|
-
manual: "enable it in Settings → Extensions"
|
|
11012
|
+
manual: "enable it in Settings → Extensions",
|
|
11013
|
+
revoked: "its build is missing on the instance; save a file to upload it again"
|
|
11014
|
+
};
|
|
11015
|
+
const getErrorMessage = (error) => {
|
|
11016
|
+
return error instanceof Error ? error.message : String(error);
|
|
11050
11017
|
};
|
|
11051
|
-
const getErrorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
11052
11018
|
/** Builds the project with the development key and uploads it, which installs or reloads it. */
|
|
11053
11019
|
const uploadBuild = async (root, context, client, development) => {
|
|
11054
11020
|
const project = await loadExtensionProject(root, development);
|
|
@@ -11073,10 +11039,7 @@ const uploadBuild = async (root, context, client, development) => {
|
|
|
11073
11039
|
else await context.output.warning(`${name}@${version} is disabled: ${disabledHints[result.disabledReason ?? "manual"]}.`);
|
|
11074
11040
|
return result;
|
|
11075
11041
|
};
|
|
11076
|
-
/**
|
|
11077
|
-
* Runs an extension on the local instance for the signed-in member: uploads each build, reloads
|
|
11078
|
-
* it on file changes, and stops it on exit, keeping its configuration and storage.
|
|
11079
|
-
*/
|
|
11042
|
+
/** Runs the extension on the local instance, reloading it on changes and stopping it on exit. */
|
|
11080
11043
|
const runDevelopment = async (context, options) => {
|
|
11081
11044
|
const { output, signal } = context;
|
|
11082
11045
|
const root = path.resolve(options.root);
|
|
@@ -11218,7 +11181,9 @@ const readPublishedRegistry = async (directory) => {
|
|
|
11218
11181
|
//#endregion
|
|
11219
11182
|
//#region src/extensions/registry/check.ts
|
|
11220
11183
|
const hash = (content) => createHash("sha256").update(content).digest("hex");
|
|
11221
|
-
const describeKey = (key) =>
|
|
11184
|
+
const describeKey = (key) => {
|
|
11185
|
+
return JSON.stringify(key, Object.keys(key).sort());
|
|
11186
|
+
};
|
|
11222
11187
|
const withoutKeys = (manifest) => {
|
|
11223
11188
|
return JSON.stringify({
|
|
11224
11189
|
...manifest,
|
|
@@ -11274,10 +11239,7 @@ const checkRevocations = (revocations, published, available) => {
|
|
|
11274
11239
|
}
|
|
11275
11240
|
return errors;
|
|
11276
11241
|
};
|
|
11277
|
-
/**
|
|
11278
|
-
* Checks the registry repository against the published site with the same rules that Andesine
|
|
11279
|
-
* instances apply on ingestion, and builds each project (its dependencies must be installed).
|
|
11280
|
-
*/
|
|
11242
|
+
/** Builds each project and checks it against the published site, as instances do on ingestion. */
|
|
11281
11243
|
const checkRegistry = async (repository, publishedDirectory, output) => {
|
|
11282
11244
|
const projects = await readRegistryProjects(repository);
|
|
11283
11245
|
const published = await readPublishedRegistry(publishedDirectory);
|
|
@@ -11351,10 +11313,7 @@ const writeVersion = async (published, siteURL, version, sourceCommit) => {
|
|
|
11351
11313
|
await writeFile(path.join(directory, VERSION_FILE), `${JSON.stringify(versionManifest, null, 2)}\n`);
|
|
11352
11314
|
return versionManifest;
|
|
11353
11315
|
};
|
|
11354
|
-
/**
|
|
11355
|
-
* Checks the registry, writes the files of new versions, then the index, which instances read;
|
|
11356
|
-
* the index comes last, so it never names files that are not published yet.
|
|
11357
|
-
*/
|
|
11316
|
+
/** Writes new versions, then the index, so the index never names unpublished files. */
|
|
11358
11317
|
const buildRegistry = async (options, output) => {
|
|
11359
11318
|
const siteURL = getSiteURL(options.siteURL);
|
|
11360
11319
|
const check = await checkRegistry(options.repository, options.published, output);
|
|
@@ -11423,6 +11382,7 @@ const initExtension = async (directory, options, output) => {
|
|
|
11423
11382
|
};
|
|
11424
11383
|
//#endregion
|
|
11425
11384
|
//#region src/extensions/register.ts
|
|
11385
|
+
const ROOT_DESCRIPTION = "Extension directory (default: current directory)";
|
|
11426
11386
|
const formatVersions = (manifests) => {
|
|
11427
11387
|
return manifests.map(({ name, version }) => `${name}@${version}`).join(", ");
|
|
11428
11388
|
};
|
|
@@ -11431,7 +11391,6 @@ const reportRegistryErrors = async (output, errors) => {
|
|
|
11431
11391
|
for (const error of errors) await output.error(error);
|
|
11432
11392
|
throw new CLIError(`The registry has ${errors.length} problem(s).`);
|
|
11433
11393
|
};
|
|
11434
|
-
const ROOT_DESCRIPTION = "Extension directory (default: current directory)";
|
|
11435
11394
|
const registerExtensions = (program, signal) => {
|
|
11436
11395
|
const getOutput = (command) => {
|
|
11437
11396
|
return createOutput(command.optsWithGlobals().interactive, signal);
|