@astryxdesign/cli 0.7.12-canary.ed58688 → 0.7.12-canary.f124c2f
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/api/component/__fixtures__/resolutions/modules.txt +1 -1
- package/assets/discover/official-packages.json +4 -0
- package/assets/docs/styling-overview.doc.mjs +3 -3
- package/assets/docs/tree/tailwind.doc.mjs +41 -1
- package/assets/templates/blocks/components/PowerSearch/usePowerSearchConfigHookUsage.doc.mjs +14 -0
- package/assets/templates/blocks/components/PowerSearch/usePowerSearchConfigHookUsage.tsx +83 -0
- package/clients/cli/lib/resolve-theme.mjs +16 -7
- package/foundation/doc-compiler/import.d.mts +5 -1
- package/foundation/doc-compiler/import.mjs +39 -6
- package/foundation/fs/module-loader.d.mts +10 -0
- package/foundation/fs/module-loader.mjs +17 -4
- package/package.json +6 -6
|
@@ -282,7 +282,7 @@ useOverlay useOverlay Overlay/useOverlay.doc.mjs Overlay/useOverlay.tsx
|
|
|
282
282
|
useOwnScrollGesture useOwnScrollGesture DateInput/DateInput.doc.mjs DateInput/useOwnScrollGesture.ts
|
|
283
283
|
usePager usePager hooks/useAnimatedLayout.doc.mjs hooks/usePager.ts
|
|
284
284
|
usePointerDragScroll usePointerDragScroll DateInput/DateInput.doc.mjs DateInput/usePointerDragScroll.ts
|
|
285
|
-
usePowerSearchConfig usePowerSearchConfig PowerSearch/
|
|
285
|
+
usePowerSearchConfig usePowerSearchConfig PowerSearch/usePowerSearchConfig.doc.mjs PowerSearch/usePowerSearchConfig.ts
|
|
286
286
|
usePowerSearchSource usePowerSearchSource PowerSearch/PowerSearch.doc.mjs PowerSearch/usePowerSearchSource.ts
|
|
287
287
|
useRenamedProp useRenamedProp hooks/useAnimatedLayout.doc.mjs hooks/useRenamedProp.ts
|
|
288
288
|
useResolvedRequired useResolvedRequired hooks/useAnimatedLayout.doc.mjs hooks/useResolvedRequired.ts
|
|
@@ -90,7 +90,7 @@ export const docs = {
|
|
|
90
90
|
{
|
|
91
91
|
type: 'code',
|
|
92
92
|
lang: 'bash',
|
|
93
|
-
label: 'Install
|
|
93
|
+
label: 'Install',
|
|
94
94
|
code: '{@pm install @astryxdesign/core @stylexjs/stylex @astryxdesign/theme-neutral}',
|
|
95
95
|
},
|
|
96
96
|
{
|
|
@@ -113,7 +113,7 @@ export const docs = {
|
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
type: 'prose',
|
|
116
|
-
text: 'For Tailwind v3, see the layer workaround in {@link generic:migration-setup}.',
|
|
116
|
+
text: 'A project with Tailwind already set up needs a smaller change, which {@link generic:tailwind} shows. For Tailwind v3, see the layer workaround in {@link generic:migration-setup}.',
|
|
117
117
|
},
|
|
118
118
|
],
|
|
119
119
|
},
|
|
@@ -162,7 +162,7 @@ export const docs = {
|
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
164
|
type: 'prose',
|
|
165
|
-
text:
|
|
165
|
+
text: "`{@command swizzle <Component>}` writes an `astryx-swizzle.json` marker into an output folder it owns (one the copy creates, an empty one, or one it marked before); every module under that folder then compiles as Astryx source, so keep copies in a folder of their own, such as the default `components/astryx`. For a folder that already holds other files it writes no marker and says how to add one by hand. With `@astryxdesign/build`'s Babel, PostCSS and Vite integrations, or `withAstryx()` under webpack, a copy under that folder compiles into `astryx-base`, below `astryx-theme`, so theme component overrides reach it as they reach the package component. Under Turbopack, and with the stock StyleX plugins above, a copy's rules land in your own styles, above `astryx-theme`, and theme component overrides do not reach it.",
|
|
166
166
|
},
|
|
167
167
|
],
|
|
168
168
|
},
|
|
@@ -19,6 +19,8 @@ export const docs = {
|
|
|
19
19
|
'tailwind-theme.css',
|
|
20
20
|
'utility classes',
|
|
21
21
|
'preflight',
|
|
22
|
+
'existing Tailwind app',
|
|
23
|
+
'cascade layer order',
|
|
22
24
|
],
|
|
23
25
|
|
|
24
26
|
sections: [
|
|
@@ -69,7 +71,45 @@ import {themes, defaultThemeSlug} from './astryx-themes';`,
|
|
|
69
71
|
},
|
|
70
72
|
{
|
|
71
73
|
type: 'prose',
|
|
72
|
-
text:
|
|
74
|
+
text: "The Tailwind bridge is the concrete example of the general interop pattern: expose another library's semantic API, but point the values at system token variables.",
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
title: 'Add Astryx to an app that already uses Tailwind',
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: 'prose',
|
|
83
|
+
text: 'The recipe in the Tailwind section is a whole `globals.css` for a new app. An app that already uses Tailwind keeps its own file: its `@import "tailwindcss"`, its `@theme` mapping, and its `:root` variables stay as they are. Add one `@layer` line above the Tailwind import and the Astryx stylesheets below it.',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: 'code',
|
|
87
|
+
lang: 'css',
|
|
88
|
+
label: 'globals.css (existing Tailwind app)',
|
|
89
|
+
code: `@layer reset, theme, base, astryx-base, astryx-theme, components, utilities;
|
|
90
|
+
|
|
91
|
+
@import "tailwindcss"; /* the app's own entry, unchanged */
|
|
92
|
+
@import "@astryxdesign/core/reset.css";
|
|
93
|
+
@import "@astryxdesign/core/astryx.css";
|
|
94
|
+
@import "@astryxdesign/theme-neutral/theme.css";
|
|
95
|
+
|
|
96
|
+
/* The app's own @theme and :root rules stay below, unchanged. */`,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
type: 'prose',
|
|
100
|
+
text: "This recipe leaves out `tailwind-theme.css`. The bridge maps Tailwind theme names to system tokens, including Tailwind's own defaults such as `rounded-lg` and `shadow-md`, so in an existing app it changes what the app's own classes paint. Add it only when the app does not use the names it maps.",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
type: 'prose',
|
|
104
|
+
text: "Astryx's theme defines its own CSS custom properties (color, spacing, radius, shadow, font, motion and more), and {@link namespace:tokens} has the full list. An app token with one of those names collides in one of two ways. An app `@theme` key takes Astryx's value, because `astryx.css` sets the tokens on `:root` above Tailwind's `theme` layer: with `@theme { --spacing-4: 1.5rem }`, the app's `gap-4` stays 16px. Marking the block `@theme inline` keeps the app's value in its utilities. An app `:root` variable replaces Astryx's value, so Astryx's own components change: `:root { --spacing-4: 1.5rem }` widens Astryx's spacing step 4 from 16px to 24px. Where the root Theme component sets a token again, such as `--color-warning`, the app's own rules inside it read Astryx's value instead. Rename any app token that shares a name.",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
type: 'prose',
|
|
108
|
+
text: "Put the `@layer` line above the app's `@import \"tailwindcss\"`, never below it. A `@layer` statement orders only the layer names the page has not seen yet, and the Tailwind import names `theme`, `base`, `components`, and `utilities` as it loads. Below that import, the statement can only add `reset`, `astryx-base`, and `astryx-theme` after Tailwind's `utilities`. That inverts the cascade: the Astryx reset then outranks every utility class in the app, and, for example, removes the borders and padding the app's utilities give its controls. Nothing reports it: the build and the browser console stay clean, and the `@layer` line still looks right in the source, so only the rendered page shows the problem.",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
type: 'prose',
|
|
112
|
+
text: 'The load-order rule from the Tailwind section still applies: `globals.css` must be the first stylesheet the page loads, so its `@layer` line names the layers first.',
|
|
73
113
|
},
|
|
74
114
|
],
|
|
75
115
|
},
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
exampleFor: 'usePowerSearchConfig',
|
|
7
|
+
name: 'usePowerSearchConfig — Filtered Directory Table',
|
|
8
|
+
displayName: 'usePowerSearchConfig — Filtered Directory Table',
|
|
9
|
+
description:
|
|
10
|
+
'A people directory with a PowerSearch bar over a Table: typed field definitions feed usePowerSearchConfig, returning the search config and an applyFilters helper that updates Table rows.',
|
|
11
|
+
isReady: true,
|
|
12
|
+
aspectRatio: 4 / 3,
|
|
13
|
+
componentsUsed: ['PowerSearch', 'Table', 'Layout'],
|
|
14
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {useState} from 'react';
|
|
6
|
+
import {VStack} from '@astryxdesign/core/Layout';
|
|
7
|
+
import {
|
|
8
|
+
PowerSearch,
|
|
9
|
+
usePowerSearchConfig,
|
|
10
|
+
} from '@astryxdesign/core/PowerSearch';
|
|
11
|
+
import type {PowerSearchFilter} from '@astryxdesign/core/PowerSearch';
|
|
12
|
+
import {Table} from '@astryxdesign/core/Table';
|
|
13
|
+
import type {TableColumn} from '@astryxdesign/core/Table';
|
|
14
|
+
|
|
15
|
+
const statusValues = [
|
|
16
|
+
{value: 'active', label: 'Active'},
|
|
17
|
+
{value: 'on-leave', label: 'On Leave'},
|
|
18
|
+
{value: 'contractor', label: 'Contractor'},
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const fieldDefs = [
|
|
22
|
+
{key: 'name', type: 'string', label: 'Name'},
|
|
23
|
+
{key: 'status', type: 'enum', label: 'Status', enumValues: statusValues},
|
|
24
|
+
{key: 'startDate', type: 'date', label: 'Start date'},
|
|
25
|
+
] as const;
|
|
26
|
+
|
|
27
|
+
interface Person extends Record<string, unknown> {
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
status: string;
|
|
31
|
+
startDate: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const people: Person[] = [
|
|
35
|
+
{id: '1', name: 'Alice Chen', status: 'active', startDate: 1672531200},
|
|
36
|
+
{id: '2', name: 'Bob Dylan', status: 'on-leave', startDate: 1680307200},
|
|
37
|
+
{id: '3', name: 'Charlie Kim', status: 'active', startDate: 1688169600},
|
|
38
|
+
{id: '4', name: 'Dana Scully', status: 'contractor', startDate: 1696118400},
|
|
39
|
+
{id: '5', name: 'Evan Wright', status: 'active', startDate: 1704067200},
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const columns: TableColumn<Person>[] = [
|
|
43
|
+
{key: 'name', header: 'Name'},
|
|
44
|
+
{
|
|
45
|
+
key: 'status',
|
|
46
|
+
header: 'Status',
|
|
47
|
+
renderCell: (person: Person) =>
|
|
48
|
+
statusValues.find(s => s.value === person.status)?.label ?? person.status,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
key: 'startDate',
|
|
52
|
+
header: 'Start Date',
|
|
53
|
+
renderCell: (person: Person) =>
|
|
54
|
+
new Date(person.startDate * 1000).toLocaleDateString('en-US', {
|
|
55
|
+
timeZone: 'UTC',
|
|
56
|
+
year: 'numeric',
|
|
57
|
+
month: 'short',
|
|
58
|
+
day: 'numeric',
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
export default function UsePowerSearchConfigHookUsage() {
|
|
64
|
+
const [filters, setFilters] = useState<PowerSearchFilter[]>([]);
|
|
65
|
+
const {config, applyFilters} = usePowerSearchConfig(
|
|
66
|
+
fieldDefs,
|
|
67
|
+
'PeopleDirectory',
|
|
68
|
+
);
|
|
69
|
+
const filteredPeople = applyFilters(filters, people);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<VStack gap={4}>
|
|
73
|
+
<PowerSearch
|
|
74
|
+
config={config}
|
|
75
|
+
filters={filters}
|
|
76
|
+
onChange={newFilters => setFilters([...newFilters])}
|
|
77
|
+
placeholder="Filter directory by name, status, start date..."
|
|
78
|
+
resultCount={filteredPeople.length}
|
|
79
|
+
/>
|
|
80
|
+
<Table data={filteredPeople} columns={columns} idKey="id" hasHover />
|
|
81
|
+
</VStack>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -73,11 +73,22 @@ function extractTheme(mod) {
|
|
|
73
73
|
return null;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Print a theme warning as one inert line. The configured theme value and the
|
|
78
|
+
* generated record come from the checkout, so a newline, an escape sequence or
|
|
79
|
+
* a bidi override in them must not rewrite the terminal. Control and format
|
|
80
|
+
* characters print as U+FFFD.
|
|
81
|
+
* @param {string} message
|
|
82
|
+
*/
|
|
83
|
+
function warnTheme(message) {
|
|
84
|
+
console.warn(message.replace(/[\p{Cc}\p{Cf}]/gu, '\uFFFD'));
|
|
85
|
+
}
|
|
86
|
+
|
|
76
87
|
/** @param {unknown} mod @param {string} specifier */
|
|
77
88
|
function resolvedThemeData(mod, specifier) {
|
|
78
89
|
const theme = extractTheme(mod);
|
|
79
90
|
if (!theme) {
|
|
80
|
-
|
|
91
|
+
warnTheme(
|
|
81
92
|
`⚠ theme: loaded "${specifier}" but could not find a theme object`,
|
|
82
93
|
);
|
|
83
94
|
return null;
|
|
@@ -100,7 +111,7 @@ export async function resolveTheme(cwd = process.cwd()) {
|
|
|
100
111
|
const loaded = await resolveRecordedTheme(cwd);
|
|
101
112
|
if (loaded.configured) {
|
|
102
113
|
if (!loaded.module) {
|
|
103
|
-
|
|
114
|
+
warnTheme(
|
|
104
115
|
`⚠ theme: ${loaded.problem ?? `could not resolve the generated default theme (${loaded.specifier})`}`,
|
|
105
116
|
);
|
|
106
117
|
return null;
|
|
@@ -130,15 +141,13 @@ export async function resolveTheme(cwd = process.cwd()) {
|
|
|
130
141
|
if (specifier.startsWith('.') || specifier.startsWith('/')) {
|
|
131
142
|
mod = tryLoadLegacyModule(specifier, cwd);
|
|
132
143
|
if (!mod) {
|
|
133
|
-
|
|
134
|
-
`⚠ theme: could not resolve file "${specifier}" from ${cwd}`,
|
|
135
|
-
);
|
|
144
|
+
warnTheme(`⚠ theme: could not resolve file "${specifier}" from ${cwd}`);
|
|
136
145
|
return null;
|
|
137
146
|
}
|
|
138
147
|
} else if (specifier.startsWith('@')) {
|
|
139
148
|
mod = tryLoadLegacyModule(specifier, cwd);
|
|
140
149
|
if (!mod) {
|
|
141
|
-
|
|
150
|
+
warnTheme(`⚠ theme: could not resolve package "${specifier}"`);
|
|
142
151
|
return null;
|
|
143
152
|
}
|
|
144
153
|
} else {
|
|
@@ -147,7 +156,7 @@ export async function resolveTheme(cwd = process.cwd()) {
|
|
|
147
156
|
tryLoadLegacyModule(conventional, cwd) ??
|
|
148
157
|
tryLoadLegacyModule(specifier, cwd);
|
|
149
158
|
if (!mod) {
|
|
150
|
-
|
|
159
|
+
warnTheme(
|
|
151
160
|
`⚠ theme: could not resolve "${specifier}" (tried ${conventional} and ${specifier})`,
|
|
152
161
|
);
|
|
153
162
|
return null;
|
|
@@ -17,7 +17,11 @@ export function importDocModule(file: string): Promise<any>;
|
|
|
17
17
|
export function importTemplateModule(file: string): Promise<any>;
|
|
18
18
|
/**
|
|
19
19
|
* Import a module natively, by file URL: how the docs API, search, and the
|
|
20
|
-
* unchecked component and hook readers have always imported docs.
|
|
20
|
+
* unchecked component and hook readers have always imported docs. A `.ts`
|
|
21
|
+
* file goes through jiti, as {@link importDocModule} imports it: Node cannot
|
|
22
|
+
* strip types from a file under node_modules, and below 22.18 it does not
|
|
23
|
+
* strip types at all, so a plain import of an installed or linked
|
|
24
|
+
* integration's `.doc.ts` fails.
|
|
21
25
|
* @param {string} file
|
|
22
26
|
* @returns {Promise<any>}
|
|
23
27
|
*/
|
|
@@ -25,7 +25,11 @@
|
|
|
25
25
|
import {pathToFileURL} from 'node:url';
|
|
26
26
|
import {createJiti} from 'jiti';
|
|
27
27
|
import {importUrl} from '../fs/import-url.mjs';
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
importUserModule,
|
|
30
|
+
readFreshInTurn,
|
|
31
|
+
readInTurn,
|
|
32
|
+
} from '../fs/module-loader.mjs';
|
|
29
33
|
import {fileStamp, recordContentRead} from '../fs/read-record.mjs';
|
|
30
34
|
|
|
31
35
|
/** @type {ReturnType<typeof createJiti> | undefined} */
|
|
@@ -79,6 +83,28 @@ function freshUrl(file) {
|
|
|
79
83
|
return url.href;
|
|
80
84
|
}
|
|
81
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Import `file` from `url`, in its turn with every other read of the file in
|
|
88
|
+
* this process (`readInTurn`, ../fs/module-loader.mjs).
|
|
89
|
+
* @param {string} file
|
|
90
|
+
* @param {string} url
|
|
91
|
+
* @returns {Promise<any>}
|
|
92
|
+
*/
|
|
93
|
+
function importInTurn(file, url) {
|
|
94
|
+
return readInTurn(file, () => importUrl(url));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Import `file` again, for a change, as a new module. Node chooses its format
|
|
99
|
+
* as for the first import. The read takes its turn without the file's
|
|
100
|
+
* CommonJS cache entry (`readFreshInTurn`, ../fs/module-loader.mjs).
|
|
101
|
+
* @param {string} file
|
|
102
|
+
* @returns {Promise<any>}
|
|
103
|
+
*/
|
|
104
|
+
function importFresh(file) {
|
|
105
|
+
return readFreshInTurn(file, () => importUrl(freshUrl(file)));
|
|
106
|
+
}
|
|
107
|
+
|
|
82
108
|
/**
|
|
83
109
|
* Import a component, hook, topic, or self-doc module: `.ts` through jiti,
|
|
84
110
|
* anything else natively.
|
|
@@ -106,28 +132,35 @@ export function importTemplateModule(file) {
|
|
|
106
132
|
jsxJiti ??= createJiti(import.meta.url, {jsx: true});
|
|
107
133
|
return jsxJiti.import(first);
|
|
108
134
|
}
|
|
109
|
-
return
|
|
135
|
+
return importInTurn(first, `file://${first}`);
|
|
110
136
|
},
|
|
111
137
|
changed =>
|
|
112
138
|
changed.endsWith('.ts')
|
|
113
139
|
? createJiti(import.meta.url, {jsx: true, moduleCache: false}).import(
|
|
114
140
|
changed,
|
|
115
141
|
)
|
|
116
|
-
:
|
|
142
|
+
: importFresh(changed),
|
|
117
143
|
);
|
|
118
144
|
}
|
|
119
145
|
|
|
120
146
|
/**
|
|
121
147
|
* Import a module natively, by file URL: how the docs API, search, and the
|
|
122
|
-
* unchecked component and hook readers have always imported docs.
|
|
148
|
+
* unchecked component and hook readers have always imported docs. A `.ts`
|
|
149
|
+
* file goes through jiti, as {@link importDocModule} imports it: Node cannot
|
|
150
|
+
* strip types from a file under node_modules, and below 22.18 it does not
|
|
151
|
+
* strip types at all, so a plain import of an installed or linked
|
|
152
|
+
* integration's `.doc.ts` fails.
|
|
123
153
|
* @param {string} file
|
|
124
154
|
* @returns {Promise<any>}
|
|
125
155
|
*/
|
|
126
156
|
export function importNativeModule(file) {
|
|
157
|
+
if (file.endsWith('.ts')) {
|
|
158
|
+
return importDocModule(file);
|
|
159
|
+
}
|
|
127
160
|
return importCurrent(
|
|
128
161
|
file,
|
|
129
162
|
'native',
|
|
130
|
-
first =>
|
|
131
|
-
changed =>
|
|
163
|
+
first => importInTurn(first, pathToFileURL(first).href),
|
|
164
|
+
changed => importFresh(changed),
|
|
132
165
|
);
|
|
133
166
|
}
|
|
@@ -40,6 +40,16 @@ export function importThemeArtifact(specifier: string, cwd: string): Promise<Rec
|
|
|
40
40
|
* @returns {Promise<T>}
|
|
41
41
|
*/
|
|
42
42
|
export function readInTurn<T>(file: string, read: () => Promise<T>): Promise<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Run `read`, a fresh import of `file`, in the file's turn (`readInTurn`),
|
|
45
|
+
* once the file is gone from Node's CommonJS cache. A new URL names a new ES
|
|
46
|
+
* module only, so a CommonJS module also needs its cache entry gone.
|
|
47
|
+
* @template T
|
|
48
|
+
* @param {string} file absolute path
|
|
49
|
+
* @param {() => Promise<T>} read
|
|
50
|
+
* @returns {Promise<T>}
|
|
51
|
+
*/
|
|
52
|
+
export function readFreshInTurn<T>(file: string, read: () => Promise<T>): Promise<T>;
|
|
43
53
|
/**
|
|
44
54
|
* Import a user-authored module, take its default export, and validate it
|
|
45
55
|
* through an authoring parser. This is the single load/validation boundary for
|
|
@@ -236,10 +236,7 @@ async function importModule(file, fresh) {
|
|
|
236
236
|
// "type", the extension, or the source's syntax. The query names a new ES
|
|
237
237
|
// module. A CommonJS module also needs its cache entry gone.
|
|
238
238
|
url.searchParams.set('astryx-fresh', String(++freshImportNonce));
|
|
239
|
-
return await
|
|
240
|
-
delete requireFromHere.cache[cacheKey(file)];
|
|
241
|
-
return import(url.href);
|
|
242
|
-
});
|
|
239
|
+
return await readFreshInTurn(file, () => import(url.href));
|
|
243
240
|
}
|
|
244
241
|
|
|
245
242
|
/**
|
|
@@ -287,6 +284,22 @@ export function readInTurn(file, read) {
|
|
|
287
284
|
return result;
|
|
288
285
|
}
|
|
289
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Run `read`, a fresh import of `file`, in the file's turn (`readInTurn`),
|
|
289
|
+
* once the file is gone from Node's CommonJS cache. A new URL names a new ES
|
|
290
|
+
* module only, so a CommonJS module also needs its cache entry gone.
|
|
291
|
+
* @template T
|
|
292
|
+
* @param {string} file absolute path
|
|
293
|
+
* @param {() => Promise<T>} read
|
|
294
|
+
* @returns {Promise<T>}
|
|
295
|
+
*/
|
|
296
|
+
export function readFreshInTurn(file, read) {
|
|
297
|
+
return readInTurn(file, () => {
|
|
298
|
+
delete requireFromHere.cache[cacheKey(file)];
|
|
299
|
+
return read();
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
290
303
|
|
|
291
304
|
/**
|
|
292
305
|
* Import a user-authored module, take its default export, and validate it
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/cli",
|
|
3
|
-
"version": "0.7.12-canary.
|
|
3
|
+
"version": "0.7.12-canary.f124c2f",
|
|
4
4
|
"displayName": "CLI",
|
|
5
5
|
"description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"zod": "^4.4.3"
|
|
126
126
|
},
|
|
127
127
|
"peerDependencies": {
|
|
128
|
-
"@astryxdesign/core": "0.7.12-canary.
|
|
128
|
+
"@astryxdesign/core": "0.7.12-canary.f124c2f"
|
|
129
129
|
},
|
|
130
130
|
"peerDependenciesMeta": {
|
|
131
131
|
"@astryxdesign/core": {
|
|
@@ -133,10 +133,10 @@
|
|
|
133
133
|
}
|
|
134
134
|
},
|
|
135
135
|
"devDependencies": {
|
|
136
|
-
"@astryxdesign/charts": "0.7.12-canary.
|
|
137
|
-
"@astryxdesign/core": "0.7.12-canary.
|
|
138
|
-
"@astryxdesign/lab": "0.7.12-canary.
|
|
139
|
-
"@astryxdesign/theme-neutral": "0.7.12-canary.
|
|
136
|
+
"@astryxdesign/charts": "0.7.12-canary.f124c2f",
|
|
137
|
+
"@astryxdesign/core": "0.7.12-canary.f124c2f",
|
|
138
|
+
"@astryxdesign/lab": "0.7.12-canary.f124c2f",
|
|
139
|
+
"@astryxdesign/theme-neutral": "0.7.12-canary.f124c2f",
|
|
140
140
|
"@heroicons/react": "^2.2.0",
|
|
141
141
|
"@stylexjs/stylex": "^0.19.0",
|
|
142
142
|
"@types/babel__core": "^7.20.5",
|