poveste 0.16.2 → 0.17.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/README.md +1 -1
- package/bin.mjs +6 -1
- package/dist/node/builtin-plugins/vanilla-support/client.d.ts +1 -1
- package/dist/node/builtin-plugins/vanilla-support/contract.d.ts +6 -0
- package/dist/node/builtin-plugins/vanilla-support/contract.js +1 -0
- package/dist/node/collect/error.d.ts +8 -1
- package/dist/node/collect/error.js +22 -1
- package/dist/node/collect/index.js +1 -2
- package/dist/node/dom/env.js +4 -1
- package/dist/node/vite.js +3 -4
- package/framework-floor.mjs +88 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ Run `npx poveste --help` for the full list of options.
|
|
|
47
47
|
|
|
48
48
|
## Requirements
|
|
49
49
|
|
|
50
|
-
Node `>=
|
|
50
|
+
Node `>=24.15.0` and Vite `^8.0.0`. See
|
|
51
51
|
[supported versions](https://poveste.dev/guide/getting-started#supported-versions) for
|
|
52
52
|
what proves each range.
|
|
53
53
|
|
package/bin.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
4
|
import process from 'node:process'
|
|
5
|
+
import { supportedFrameworks } from './framework-floor.mjs'
|
|
5
6
|
import { supportedNode } from './node-floor.mjs'
|
|
6
7
|
|
|
7
8
|
// Before the CLI is imported, not inside it: on a Node below the floor the import
|
|
@@ -12,7 +13,11 @@ import { supportedNode } from './node-floor.mjs'
|
|
|
12
13
|
// Imported dynamically for the same reason. A static import is parsed with this
|
|
13
14
|
// module, before a line of it runs, so syntax `dist/` may carry would win the race
|
|
14
15
|
// against the message explaining it.
|
|
15
|
-
|
|
16
|
+
// The framework floor goes here for the same reason: on a framework below a
|
|
17
|
+
// plugin's peer, importing the CLI fails first and names neither (#1062). Not for
|
|
18
|
+
// `--help` or `--version`, which load no command and so cannot reach that failure.
|
|
19
|
+
const informational = process.argv.slice(2).some(arg => ['--help', '-h', '--version', '-v'].includes(arg))
|
|
20
|
+
if (supportedNode() && (informational || supportedFrameworks())) {
|
|
16
21
|
import('./dist/node/bin.js').catch((error) => {
|
|
17
22
|
// `exitCode`, not `exit`: the error is the last thing written, and forcing the
|
|
18
23
|
// process out on the same tick truncates it on a pipe.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ClientSupportPlugin } from '@poveste/shared';
|
|
2
|
+
import type { Component } from '@poveste/vendors/vue';
|
|
3
|
+
import type * as client from './client';
|
|
4
|
+
type Satisfies<T extends ClientSupportPlugin<Component>> = T;
|
|
5
|
+
export type ClientContract = Satisfies<typeof client>;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/** What this module needs of a thrown value to be able to describe it. */
|
|
2
|
+
interface ErrorLike {
|
|
3
|
+
name: string;
|
|
4
|
+
message: string;
|
|
5
|
+
stack?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function serializeError(error: unknown, seen?: WeakSet<ErrorLike>): unknown;
|
|
2
8
|
export declare function deserializeError(value: unknown): unknown;
|
|
9
|
+
export {};
|
|
@@ -7,6 +7,27 @@ const MARK = 'pvt:error';
|
|
|
7
7
|
function isSerialized(value) {
|
|
8
8
|
return typeof value === 'object' && value !== null && value.kind === MARK;
|
|
9
9
|
}
|
|
10
|
+
/*
|
|
11
|
+
* Not `instanceof Error`, and not `Error.isError` either. A `DOMException` from
|
|
12
|
+
* jsdom fails both — the first because `runScripts: 'dangerously'` makes jsdom a
|
|
13
|
+
* separate realm, the second because jsdom's is a webidl2js object rather than a
|
|
14
|
+
* genuine error — while carrying a name, a message and a stack. It is what a
|
|
15
|
+
* story's own DOM call throws, and a clone of one retains nothing, so the host
|
|
16
|
+
* received `{}` (#1097).
|
|
17
|
+
*
|
|
18
|
+
* A `stack` is required and not merely read: `{ name, message }` is a shape a
|
|
19
|
+
* story may legitimately throw, and it should arrive as the data it is.
|
|
20
|
+
*/
|
|
21
|
+
function errorLike(value) {
|
|
22
|
+
if (Error.isError(value)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
if (typeof value !== 'object' || value === null) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const { name, message, stack } = value;
|
|
29
|
+
return typeof name === 'string' && typeof message === 'string' && typeof stack === 'string';
|
|
30
|
+
}
|
|
10
31
|
// A property the clone rejects takes the whole message down with it, which is worse
|
|
11
32
|
// than dropping the property.
|
|
12
33
|
function cloneable(value) {
|
|
@@ -25,7 +46,7 @@ function cloneable(value) {
|
|
|
25
46
|
* the error it was called to describe and replace it with its own.
|
|
26
47
|
*/
|
|
27
48
|
export function serializeError(error, seen = new WeakSet()) {
|
|
28
|
-
if (!(error
|
|
49
|
+
if (!errorLike(error)) {
|
|
29
50
|
return cloneable(error) ? error : String(error);
|
|
30
51
|
}
|
|
31
52
|
if (seen.has(error)) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { cpus } from 'node:os';
|
|
2
|
-
import { escapeRegExp } from '@poveste/shared';
|
|
3
2
|
import path, { relative } from 'pathe';
|
|
4
3
|
import pc from 'picocolors';
|
|
5
4
|
import { TEMP_PATH } from '../alias.js';
|
|
@@ -25,7 +24,7 @@ export function useCollectStories(options, ctx) {
|
|
|
25
24
|
// @TODO temporary fix for https://github.com/histoire-dev/histoire/issues/409
|
|
26
25
|
/vite\w*\/dist\/client\/(client|env).mjs/,
|
|
27
26
|
...ctx.config.viteNodeInlineDeps ?? [],
|
|
28
|
-
new RegExp(
|
|
27
|
+
new RegExp(RegExp.escape(path.resolve(TEMP_PATH, 'plugins'))),
|
|
29
28
|
],
|
|
30
29
|
transformMode: ctx.config.viteNodeTransformMode,
|
|
31
30
|
});
|
package/dist/node/dom/env.js
CHANGED
|
@@ -23,7 +23,10 @@ function createVirtualConsole() {
|
|
|
23
23
|
if (type === JSDOM_ERROR_CSS_PARSING)
|
|
24
24
|
return;
|
|
25
25
|
if (type === JSDOM_ERROR_UNHANDLED_EXCEPTION) {
|
|
26
|
-
|
|
26
|
+
// `Error.isError` and not `instanceof`: the cause was constructed inside
|
|
27
|
+
// jsdom's realm, where `instanceof Error` is false and the stack — the
|
|
28
|
+
// only part that says which line threw — is discarded (#1093).
|
|
29
|
+
globalThis.console.error((Error.isError(err.cause) ? err.cause.stack : undefined) ?? err.message);
|
|
27
30
|
}
|
|
28
31
|
else {
|
|
29
32
|
globalThis.console.error(err.message);
|
package/dist/node/vite.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { escapeRegExp } from '@poveste/shared';
|
|
4
3
|
import { lookup as lookupMime } from 'mrmime';
|
|
5
4
|
import { dirname, join, relative } from 'pathe';
|
|
6
5
|
import { loadConfigFromFile as loadViteConfigFromFile, mergeConfig as mergeViteConfig, searchForWorkspaceRoot, } from 'vite';
|
|
@@ -347,7 +346,7 @@ export async function getViteConfigWithPlugins(isServer, ctx) {
|
|
|
347
346
|
if (/\.(?:vue|js)(?:$|\?)/.test(id)) {
|
|
348
347
|
const original = code;
|
|
349
348
|
for (const [flag, value] of Object.entries(flags)) {
|
|
350
|
-
code = code.replace(new RegExp(
|
|
349
|
+
code = code.replace(new RegExp(RegExp.escape(flag), 'g'), value);
|
|
351
350
|
}
|
|
352
351
|
if (original !== code)
|
|
353
352
|
return code;
|
|
@@ -407,11 +406,11 @@ export async function getViteConfigWithPlugins(isServer, ctx) {
|
|
|
407
406
|
['vue', 'vue'],
|
|
408
407
|
].reduce((acc, [name, entry]) => {
|
|
409
408
|
acc.push({
|
|
410
|
-
find: new RegExp(`^${
|
|
409
|
+
find: new RegExp(`^${RegExp.escape(name)}$`),
|
|
411
410
|
replacement: `@poveste/vendors/${entry}`,
|
|
412
411
|
});
|
|
413
412
|
acc.push({
|
|
414
|
-
find: new RegExp(`^${
|
|
413
|
+
find: new RegExp(`^${RegExp.escape(name)}/`),
|
|
415
414
|
replacement: `@poveste/vendors/${entry}/`,
|
|
416
415
|
});
|
|
417
416
|
return acc;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// The framework check the CLI makes before it loads anything, beside the Node one.
|
|
2
|
+
//
|
|
3
|
+
// A framework plugin declares its framework as a peer, and the package manager
|
|
4
|
+
// enforces that well — until a reader takes `--legacy-peer-deps`, which npm's own
|
|
5
|
+
// ERESOLVE output suggests. On Nuxt 3 what they meet next is `Cannot find package
|
|
6
|
+
// 'vite'`: Nuxt 4 hoists the `vite@^8` Poveste imports and Nuxt 3 does not. That
|
|
7
|
+
// failure comes from importing the CLI's commands, before the config — and so the
|
|
8
|
+
// plugin — is loaded at all, which is why the plugin cannot check its own peer in
|
|
9
|
+
// time and this file does (#1062).
|
|
10
|
+
//
|
|
11
|
+
// Nuxt only, until a second instance is reported. One measured case does not
|
|
12
|
+
// justify holding six plugins' peers here; another is one line in `PEERS`.
|
|
13
|
+
//
|
|
14
|
+
// Plain ES2015 beside `node-floor.mjs`, for the reason that file gives.
|
|
15
|
+
|
|
16
|
+
import { readFileSync, writeSync } from 'node:fs'
|
|
17
|
+
import { dirname, join } from 'node:path'
|
|
18
|
+
import process from 'node:process'
|
|
19
|
+
import { floorOf, isBelow } from './node-floor.mjs'
|
|
20
|
+
|
|
21
|
+
/** Each plugin whose framework is checked, and the peer that names it. */
|
|
22
|
+
export const PEERS = {
|
|
23
|
+
'@poveste/plugin-nuxt': 'nuxt',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The floor of a `^x.y.z` or `>=x.y.z` range, or `null` for any other shape.
|
|
28
|
+
*
|
|
29
|
+
* Only the floor: a version above a caret's major is the package manager's to
|
|
30
|
+
* refuse, and saying nothing about a shape this cannot read keeps our own
|
|
31
|
+
* manifest drift from becoming a reader's failed command.
|
|
32
|
+
*/
|
|
33
|
+
export function rangeFloor(range) {
|
|
34
|
+
return floorOf(String(range ?? '').trim().replace(/^\^/, '>='))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The manifest of `name` as Node would find it from `dir`, or `null`.
|
|
39
|
+
*
|
|
40
|
+
* Only a missing file sends the walk upward, as it does Node's. A manifest that
|
|
41
|
+
* is there and unreadable ends it: going on would read an ancestor's copy, which
|
|
42
|
+
* in a monorepo can be another package's framework at another version.
|
|
43
|
+
*/
|
|
44
|
+
export function installedManifest(name, dir) {
|
|
45
|
+
for (let current = dir; ; current = dirname(current)) {
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(readFileSync(join(current, 'node_modules', name, 'package.json'), 'utf8'))
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error?.code !== 'ENOENT' || dirname(current) === current) {
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The Node message's shape, so the two read as one family. */
|
|
58
|
+
export function unsupportedFrameworkMessage(framework, version, plugin, range) {
|
|
59
|
+
return `You are using ${framework} ${version}. ${plugin} requires ${framework} ${range}. Please upgrade ${framework}.`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** A sentence per checked plugin whose installed framework is below its peer floor. */
|
|
63
|
+
export function frameworkProblems(dir) {
|
|
64
|
+
const problems = []
|
|
65
|
+
|
|
66
|
+
for (const [plugin, framework] of Object.entries(PEERS)) {
|
|
67
|
+
const range = installedManifest(plugin, dir)?.peerDependencies?.[framework]
|
|
68
|
+
const floor = rangeFloor(range)
|
|
69
|
+
const version = installedManifest(framework, dir)?.version
|
|
70
|
+
if (floor && version && isBelow(version, floor)) {
|
|
71
|
+
problems.push(unsupportedFrameworkMessage(framework, version, plugin, range))
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return problems
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Whether the project's frameworks may run the CLI, saying so on stderr when not. */
|
|
79
|
+
export function supportedFrameworks(dir = process.cwd()) {
|
|
80
|
+
const problems = frameworkProblems(dir)
|
|
81
|
+
if (problems.length === 0) {
|
|
82
|
+
return true
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
writeSync(2, `${problems.join('\n')}\n`)
|
|
86
|
+
process.exitCode = 1
|
|
87
|
+
return false
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poveste",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.17.1",
|
|
5
5
|
"description": "Interactive component playgrounds for Vue, Nuxt, Svelte, SvelteKit and Quasar — a drop-in fork of histoire, with Quasar support histoire does not ship.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Sorin Gitlan",
|
|
@@ -61,23 +61,24 @@
|
|
|
61
61
|
"client.d.ts",
|
|
62
62
|
"client.js",
|
|
63
63
|
"dist",
|
|
64
|
+
"framework-floor.mjs",
|
|
64
65
|
"index.d.ts",
|
|
65
66
|
"node-floor.mjs",
|
|
66
67
|
"plugin.d.ts",
|
|
67
68
|
"plugin.js"
|
|
68
69
|
],
|
|
69
70
|
"engines": {
|
|
70
|
-
"node": ">=
|
|
71
|
+
"node": ">=24.15.0"
|
|
71
72
|
},
|
|
72
73
|
"peerDependencies": {
|
|
73
74
|
"vite": "^8.0.0"
|
|
74
75
|
},
|
|
75
76
|
"dependencies": {
|
|
76
77
|
"@11ty/gray-matter": "^3.0.0",
|
|
77
|
-
"@poveste/app": "^0.
|
|
78
|
-
"@poveste/controls": "^0.
|
|
79
|
-
"@poveste/shared": "^0.
|
|
80
|
-
"@poveste/vendors": "^0.
|
|
78
|
+
"@poveste/app": "^0.17.1",
|
|
79
|
+
"@poveste/controls": "^0.17.1",
|
|
80
|
+
"@poveste/shared": "^0.17.1",
|
|
81
|
+
"@poveste/vendors": "^0.17.1",
|
|
81
82
|
"change-case": "^5.4.4",
|
|
82
83
|
"chokidar": "^5.0.0",
|
|
83
84
|
"defu": "^6.1.4",
|