@astryxdesign/cli 0.7.11 → 0.7.12-canary.ccb4a6d
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/build/kit/rank.mjs +21 -4
- package/api/build/kit/words.d.mts +1 -0
- package/api/build/kit/words.mjs +1 -1
- package/api/icon/_adapter.d.mts +3 -2
- package/api/icon/_adapter.mjs +8 -2
- package/api/icon/_authoring.d.mts +1 -0
- package/api/icon/_authoring.mjs +586 -66
- package/api/icon/_default-look.d.mts +155 -0
- package/api/icon/_default-look.mjs +474 -0
- package/api/icon/_records.d.mts +1 -1
- package/api/icon/_records.mjs +1 -0
- package/api/icon/add/add.mjs +224 -38
- package/api/icon/icon.type.d.mts +22 -2
- package/api/icon/icon.type.mjs +6 -2
- package/api/icon/iconAdd.doc.mjs +2 -2
- package/api/icon/iconNewDefinition.doc.mjs +3 -2
- package/api/icon/iconNewSet.doc.mjs +4 -4
- package/api/icon/search/search.mjs +10 -9
- package/api/integration/add-helpers.d.mts +11 -1
- package/api/integration/add-helpers.mjs +5 -2
- package/api/integration/authoring-checks.d.mts +0 -2
- package/api/integration/authoring-checks.mjs +1 -6
- package/api/logger.mjs +2 -1
- package/api/swizzle/_adapter.d.mts +1 -0
- package/api/swizzle/_adapter.mjs +4 -1
- package/api/swizzle/_moduleGraph.d.mts +171 -0
- package/api/swizzle/_moduleGraph.mjs +795 -0
- package/api/swizzle/copy/copy.d.mts +2 -43
- package/api/swizzle/copy/copy.mjs +195 -314
- package/api/swizzle/swizzle.d.mts +0 -2
- package/api/swizzle/swizzle.doc.mjs +9 -4
- package/api/swizzle/swizzle.mjs +3 -7
- package/api/swizzle/swizzle.type.d.mts +2 -1
- package/api/swizzle/swizzle.type.mjs +3 -2
- package/assets/discover/official-packages.json +20 -0
- package/assets/docs/tree/icon-sets.doc.mjs +11 -5
- package/assets/templates/blocks/components/Table/TableRowIndexTable.doc.mjs +1 -1
- package/assets/templates/blocks/components/Table/TableRowIndexTable.tsx +2 -2
- package/assets/templates/pages/course-detail/page.tsx +699 -0
- package/assets/templates/pages/course-detail/template.doc.mjs +37 -0
- package/assets/templates/pages/file-explorer/page.tsx +103 -79
- package/assets/templates/pages/table-grouped/page.tsx +160 -232
- package/assets/templates/pages/table-grouped/template.doc.mjs +0 -2
- package/assets/templates/pages/theme-showcase/page.tsx +724 -792
- package/assets/templates/pages/theme-showcase/template.doc.mjs +4 -5
- package/authoring/doctypes/template/type.ts +1 -0
- package/clients/cli/commands/experimental/icon.mjs +31 -10
- package/clients/cli/commands/experimental-icon-add.doc.mjs +1 -1
- package/clients/cli/commands/experimental-icon-new-definition.doc.mjs +2 -1
- package/clients/cli/commands/experimental-icon-new-set.doc.mjs +2 -2
- package/clients/cli/commands/swizzle.doc.mjs +8 -3
- package/clients/cli/commands/swizzle.mjs +21 -9
- package/foundation/discovery/component-loader.d.mts +1 -1
- package/foundation/discovery/doc-types.mjs +9 -2
- package/foundation/discovery/icon-ranking.d.mts +27 -3
- package/foundation/discovery/icon-ranking.mjs +125 -8
- package/foundation/discovery/icon-set-checks.mjs +44 -35
- package/foundation/discovery/icon-set-discovery.d.mts +13 -0
- package/foundation/discovery/icon-set-discovery.mjs +25 -0
- package/foundation/discovery/icon-set-writer.d.mts +238 -16
- package/foundation/discovery/icon-set-writer.mjs +676 -79
- package/foundation/discovery/module-exports.d.mts +3 -2
- package/foundation/discovery/module-exports.mjs +167 -37
- package/foundation/fs/paths.d.mts +2 -1
- package/foundation/fs/paths.mjs +3 -4
- package/foundation/text/shell-arg.d.mts +14 -0
- package/foundation/text/shell-arg.mjs +17 -0
- package/package.json +6 -6
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The variants and default variant a command declares.
|
|
6
|
+
* @typedef {object} Looks
|
|
7
|
+
* @property {string[]} variants
|
|
8
|
+
* @property {string} default
|
|
9
|
+
* @property {boolean} [named] whether `--default-variant` named the default
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* What a set's icons draw now, read from the look words of the library
|
|
13
|
+
* exports its generated module re-exports.
|
|
14
|
+
* @typedef {object} DrawnLooks
|
|
15
|
+
* @property {string} module the library most of the set's icons come from
|
|
16
|
+
* @property {Array<Set<string>>} positions that library's look positions,
|
|
17
|
+
* the last word of a name first; empty when its names encode no looks
|
|
18
|
+
* @property {Array<string | null>} words the word most icons' exports have
|
|
19
|
+
* at each position
|
|
20
|
+
* @property {number} icons how many of the set's icons come from it
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {import('../../foundation/discovery/icon-set-discovery.mjs').DiscoveredIconSet} LookSet
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* A library's look words in the order its names write them, one position
|
|
27
|
+
* after another: `filled or outline; 24; wght300, wght400, wght500`.
|
|
28
|
+
* @param {string[][]} positions each position's words, sorted, the last
|
|
29
|
+
* word of a name first
|
|
30
|
+
*/
|
|
31
|
+
export function describedLooks(positions: string[][]): string;
|
|
32
|
+
/**
|
|
33
|
+
* What the set's icons draw now ({@link DrawnLooks}), or null when no icon
|
|
34
|
+
* re-exports a named library export.
|
|
35
|
+
* @param {LookSet} set
|
|
36
|
+
* @param {string} packageDir
|
|
37
|
+
* @param {(module: string) => Array<Set<string>> | null} positionsOf the
|
|
38
|
+
* look positions of a library the set's generated module names
|
|
39
|
+
* @param {{module?: string}} [options] `module`: read only the icons that
|
|
40
|
+
* come from this library
|
|
41
|
+
* @returns {DrawnLooks | null}
|
|
42
|
+
*/
|
|
43
|
+
export function drawnLooks(set: LookSet, packageDir: string, positionsOf: (module: string) => Array<Set<string>> | null, options?: {
|
|
44
|
+
module?: string;
|
|
45
|
+
}): DrawnLooks | null;
|
|
46
|
+
/**
|
|
47
|
+
* The variants and default variant to write for a command that declares
|
|
48
|
+
* looks, and whether the set's icons must move to a new look. Every path
|
|
49
|
+
* that writes `default.variant` uses it:
|
|
50
|
+
*
|
|
51
|
+
* - The drawn look is read from every look word of the exports the set
|
|
52
|
+
* wraps (`drawn`), or, with no icons from the library yet, is the look
|
|
53
|
+
* the library is wrapped in by default.
|
|
54
|
+
* - A named default must be a look word the library has.
|
|
55
|
+
* - A named default other than the drawn look moves the icons only on a
|
|
56
|
+
* refresh (`library` given), where each glyph that has the look takes it;
|
|
57
|
+
* in place it is refused with the refresh command.
|
|
58
|
+
* - With none named, the default is the drawn look, which `--variants` must
|
|
59
|
+
* list.
|
|
60
|
+
*
|
|
61
|
+
* A library whose names encode no looks has no look words: there the named
|
|
62
|
+
* variant, the set's current default, or the first variant is the default.
|
|
63
|
+
* Its icons keep their exports on every path, so a set with icons keeps a
|
|
64
|
+
* declared default, `--variants` must list it, and with none declared the
|
|
65
|
+
* command names it.
|
|
66
|
+
* @param {object} args
|
|
67
|
+
* @param {string} args.name the set
|
|
68
|
+
* @param {Looks | null} args.given the variants and default the command names
|
|
69
|
+
* @param {string | undefined} args.current the set's `default.variant`
|
|
70
|
+
* @param {number} args.icons how many icons the set has
|
|
71
|
+
* @param {DrawnLooks | null} args.drawn what the set's icons draw now
|
|
72
|
+
* @param {{module: string, positions: Array<Set<string>>} | null} args.library
|
|
73
|
+
* the library `--from` wraps; null in place
|
|
74
|
+
* @returns {{looks: Looks | null, moved: boolean}}
|
|
75
|
+
*/
|
|
76
|
+
export function resolveDefaultLook({ name, given, current, icons, drawn, library, }: {
|
|
77
|
+
name: string;
|
|
78
|
+
given: Looks | null;
|
|
79
|
+
current: string | undefined;
|
|
80
|
+
icons: number;
|
|
81
|
+
drawn: DrawnLooks | null;
|
|
82
|
+
library: {
|
|
83
|
+
module: string;
|
|
84
|
+
positions: Array<Set<string>>;
|
|
85
|
+
} | null;
|
|
86
|
+
}): {
|
|
87
|
+
looks: Looks | null;
|
|
88
|
+
moved: boolean;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The command that declares `variant` beside the set's variants. It names
|
|
92
|
+
* the default variant the set keeps, so it runs as printed.
|
|
93
|
+
* @param {LookSet} set
|
|
94
|
+
* @param {string} variant
|
|
95
|
+
* @param {DrawnLooks | null} drawn
|
|
96
|
+
* @returns {{name: string, reason: string}}
|
|
97
|
+
*/
|
|
98
|
+
export function declareVariantSuggestion(set: LookSet, variant: string, drawn: DrawnLooks | null): {
|
|
99
|
+
name: string;
|
|
100
|
+
reason: string;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Check that `add --variant` may add `variant` to the set's icons: a look
|
|
104
|
+
* word the library has, not the look each icon's own export draws (the
|
|
105
|
+
* default, declared or drawn), and declared by the set.
|
|
106
|
+
* @param {object} args
|
|
107
|
+
* @param {LookSet} args.set
|
|
108
|
+
* @param {string} args.variant
|
|
109
|
+
* @param {string} args.module the module the variant comes from
|
|
110
|
+
* @param {Array<Set<string>>} args.positions that module's look positions
|
|
111
|
+
* @param {DrawnLooks | null} args.drawn what the set's icons draw now
|
|
112
|
+
*/
|
|
113
|
+
export function checkVariantLook({ set, variant, module, positions, drawn }: {
|
|
114
|
+
set: LookSet;
|
|
115
|
+
variant: string;
|
|
116
|
+
module: string;
|
|
117
|
+
positions: Array<Set<string>>;
|
|
118
|
+
drawn: DrawnLooks | null;
|
|
119
|
+
}): void;
|
|
120
|
+
/**
|
|
121
|
+
* The variants and default variant a command declares.
|
|
122
|
+
*/
|
|
123
|
+
export type Looks = {
|
|
124
|
+
variants: string[];
|
|
125
|
+
default: string;
|
|
126
|
+
/**
|
|
127
|
+
* whether `--default-variant` named the default
|
|
128
|
+
*/
|
|
129
|
+
named?: boolean | undefined;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* What a set's icons draw now, read from the look words of the library
|
|
133
|
+
* exports its generated module re-exports.
|
|
134
|
+
*/
|
|
135
|
+
export type DrawnLooks = {
|
|
136
|
+
/**
|
|
137
|
+
* the library most of the set's icons come from
|
|
138
|
+
*/
|
|
139
|
+
module: string;
|
|
140
|
+
/**
|
|
141
|
+
* that library's look positions,
|
|
142
|
+
* the last word of a name first; empty when its names encode no looks
|
|
143
|
+
*/
|
|
144
|
+
positions: Array<Set<string>>;
|
|
145
|
+
/**
|
|
146
|
+
* the word most icons' exports have
|
|
147
|
+
* at each position
|
|
148
|
+
*/
|
|
149
|
+
words: Array<string | null>;
|
|
150
|
+
/**
|
|
151
|
+
* how many of the set's icons come from it
|
|
152
|
+
*/
|
|
153
|
+
icons: number;
|
|
154
|
+
};
|
|
155
|
+
export type LookSet = import("../../foundation/discovery/icon-set-discovery.mjs").DiscoveredIconSet;
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The one rule for an icon set's default variant: it is the look each
|
|
5
|
+
* icon's own export draws.
|
|
6
|
+
* @input the set's data and generated module, the wrapped library's look
|
|
7
|
+
* words, and the variants and default variant a command names
|
|
8
|
+
* @output the variants and default variant to write, or an AstryxError that
|
|
9
|
+
* names the library's look words, the command that moves the look, or the
|
|
10
|
+
* variant to add when the library's names name no looks
|
|
11
|
+
* @position used by `new-set` (create, refresh, in place) and by
|
|
12
|
+
* `add --variant` (one icon or `--all`); every command that writes or keeps
|
|
13
|
+
* `default.variant`, or adds a look, asks this module first
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {AstryxError} from '../error.mjs';
|
|
17
|
+
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
18
|
+
import {
|
|
19
|
+
generatedModulePath,
|
|
20
|
+
generatedOrigins,
|
|
21
|
+
iconIdOf,
|
|
22
|
+
preferredLook,
|
|
23
|
+
sameIconModule,
|
|
24
|
+
splitLook,
|
|
25
|
+
} from '../../foundation/discovery/icon-set-writer.mjs';
|
|
26
|
+
import {shellArg} from '../../foundation/text/shell-arg.mjs';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The variants and default variant a command declares.
|
|
30
|
+
* @typedef {object} Looks
|
|
31
|
+
* @property {string[]} variants
|
|
32
|
+
* @property {string} default
|
|
33
|
+
* @property {boolean} [named] whether `--default-variant` named the default
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* What a set's icons draw now, read from the look words of the library
|
|
38
|
+
* exports its generated module re-exports.
|
|
39
|
+
* @typedef {object} DrawnLooks
|
|
40
|
+
* @property {string} module the library most of the set's icons come from
|
|
41
|
+
* @property {Array<Set<string>>} positions that library's look positions,
|
|
42
|
+
* the last word of a name first; empty when its names encode no looks
|
|
43
|
+
* @property {Array<string | null>} words the word most icons' exports have
|
|
44
|
+
* at each position
|
|
45
|
+
* @property {number} icons how many of the set's icons come from it
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @typedef {import('../../foundation/discovery/icon-set-discovery.mjs').DiscoveredIconSet} LookSet
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A library's look words in the order its names write them, one position
|
|
54
|
+
* after another: `filled or outline; 24; wght300, wght400, wght500`.
|
|
55
|
+
* @param {string[][]} positions each position's words, sorted, the last
|
|
56
|
+
* word of a name first
|
|
57
|
+
*/
|
|
58
|
+
export function describedLooks(positions) {
|
|
59
|
+
return [...positions]
|
|
60
|
+
.reverse()
|
|
61
|
+
.map(words =>
|
|
62
|
+
words.length > 3
|
|
63
|
+
? `${words[0]} to ${words.at(-1)}`
|
|
64
|
+
: words.join(words.length === 2 ? ' or ' : ', '),
|
|
65
|
+
)
|
|
66
|
+
.join('; ');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** @param {Array<Set<string>>} positions */
|
|
70
|
+
const sortedWords = positions =>
|
|
71
|
+
positions.map(position => [...position].sort());
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The words of the positions that name a style (`filled`, `outline`), not
|
|
75
|
+
* only numbers (`24`, `wght400`): the words a variant is usually named by.
|
|
76
|
+
* @param {Array<Set<string>>} positions
|
|
77
|
+
*/
|
|
78
|
+
function styleWords(positions) {
|
|
79
|
+
return sortedWords(positions)
|
|
80
|
+
.filter(words => words.some(word => !/^[a-z]*\d+$/u.test(word)))
|
|
81
|
+
.reverse()
|
|
82
|
+
.flat();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The look the set's icons draw at the first position, in name order, whose
|
|
87
|
+
* drawn word is one of `among`; else at the first style position.
|
|
88
|
+
* @param {Array<Set<string>>} positions
|
|
89
|
+
* @param {Array<string | null>} words the drawn word at each position
|
|
90
|
+
* @param {string[]} [among]
|
|
91
|
+
* @returns {string | null}
|
|
92
|
+
*/
|
|
93
|
+
function drawnWord(positions, words, among = []) {
|
|
94
|
+
for (let index = positions.length - 1; index >= 0; index--) {
|
|
95
|
+
const word = words[index];
|
|
96
|
+
if (word != null && among.includes(word)) return word;
|
|
97
|
+
}
|
|
98
|
+
for (let index = positions.length - 1; index >= 0; index--) {
|
|
99
|
+
const word = words[index];
|
|
100
|
+
if (
|
|
101
|
+
word != null &&
|
|
102
|
+
[...positions[index]].some(w => !/^[a-z]*\d+$/u.test(w))
|
|
103
|
+
)
|
|
104
|
+
return word;
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* What the set's icons draw now ({@link DrawnLooks}), or null when no icon
|
|
111
|
+
* re-exports a named library export.
|
|
112
|
+
* @param {LookSet} set
|
|
113
|
+
* @param {string} packageDir
|
|
114
|
+
* @param {(module: string) => Array<Set<string>> | null} positionsOf the
|
|
115
|
+
* look positions of a library the set's generated module names
|
|
116
|
+
* @param {{module?: string}} [options] `module`: read only the icons that
|
|
117
|
+
* come from this library
|
|
118
|
+
* @returns {DrawnLooks | null}
|
|
119
|
+
*/
|
|
120
|
+
export function drawnLooks(set, packageDir, positionsOf, options = {}) {
|
|
121
|
+
const origins = generatedOrigins(
|
|
122
|
+
packageDir,
|
|
123
|
+
generatedModulePath(set, packageDir),
|
|
124
|
+
);
|
|
125
|
+
/** @type {Map<string, string[]>} */
|
|
126
|
+
const byModule = new Map();
|
|
127
|
+
for (const icon of set.data.icons) {
|
|
128
|
+
if ((icon.module ?? set.data.module) !== set.data.module) continue;
|
|
129
|
+
const origin = origins.get(icon.export);
|
|
130
|
+
if (!origin || origin.source === 'default') continue;
|
|
131
|
+
if (
|
|
132
|
+
options.module != null &&
|
|
133
|
+
!sameIconModule(origin.module, options.module)
|
|
134
|
+
)
|
|
135
|
+
continue;
|
|
136
|
+
const sources = byModule.get(origin.module) ?? [];
|
|
137
|
+
sources.push(origin.source);
|
|
138
|
+
byModule.set(origin.module, sources);
|
|
139
|
+
}
|
|
140
|
+
const ranked = [...byModule].sort(
|
|
141
|
+
(a, b) =>
|
|
142
|
+
b[1].length - a[1].length || (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0),
|
|
143
|
+
);
|
|
144
|
+
if (ranked.length === 0) return null;
|
|
145
|
+
for (const [module, sources] of ranked) {
|
|
146
|
+
const positions = positionsOf(module) ?? [];
|
|
147
|
+
if (positions.length === 0) continue;
|
|
148
|
+
/** @type {Array<Map<string, number>>} */
|
|
149
|
+
const counts = positions.map(() => new Map());
|
|
150
|
+
for (const source of sources) {
|
|
151
|
+
const {look} = splitLook(iconIdOf(source).split('-'), positions);
|
|
152
|
+
look.forEach((word, index) => {
|
|
153
|
+
if (word != null) {
|
|
154
|
+
counts[index].set(word, (counts[index].get(word) ?? 0) + 1);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const words = counts.map(count => {
|
|
159
|
+
/** @type {string | null} */
|
|
160
|
+
let best = null;
|
|
161
|
+
let most = 0;
|
|
162
|
+
for (const [word, n] of [...count].sort((a, b) =>
|
|
163
|
+
a[0] < b[0] ? -1 : 1,
|
|
164
|
+
)) {
|
|
165
|
+
if (n > most) {
|
|
166
|
+
best = word;
|
|
167
|
+
most = n;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return best;
|
|
171
|
+
});
|
|
172
|
+
return {module, positions, words, icons: sources.length};
|
|
173
|
+
}
|
|
174
|
+
const [module, sources] = ranked[0];
|
|
175
|
+
return {module, positions: [], words: [], icons: sources.length};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The refusal for a look word the library does not have.
|
|
180
|
+
* @param {string} word
|
|
181
|
+
* @param {string} flag `--default-variant` or `--variant`
|
|
182
|
+
* @param {string} module
|
|
183
|
+
* @param {Array<Set<string>>} positions
|
|
184
|
+
*/
|
|
185
|
+
function unknownLook(word, flag, module, positions) {
|
|
186
|
+
return new AstryxError(
|
|
187
|
+
`"${word}" is no look of ${module}: its exports name their looks with ${describedLooks(sortedWords(positions))}. Name one of these words, so each icon's export draws that look.`,
|
|
188
|
+
styleWords(positions).map(each => ({
|
|
189
|
+
name: `${flag} ${each}`,
|
|
190
|
+
reason: `a look ${module} names`,
|
|
191
|
+
})),
|
|
192
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* The command that wraps the library again in a new default look.
|
|
198
|
+
* @param {string} name
|
|
199
|
+
* @param {string | undefined} module
|
|
200
|
+
* @param {Looks} looks
|
|
201
|
+
*/
|
|
202
|
+
function refreshCommand(name, module, looks) {
|
|
203
|
+
return `astryx experimental icon new-set ${name} --from ${module ? shellArg(module) : '<module>'} --variants ${looks.variants.join(',')} --default-variant ${looks.default}`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* The refusal for a default variant that would move in place.
|
|
208
|
+
* @param {string} name
|
|
209
|
+
* @param {number} count icons that draw `now`
|
|
210
|
+
* @param {string} now the look they draw
|
|
211
|
+
* @param {Looks} looks
|
|
212
|
+
* @param {string | undefined} module
|
|
213
|
+
* @param {string | undefined} current
|
|
214
|
+
*/
|
|
215
|
+
function inPlaceMove(name, count, now, looks, module, current) {
|
|
216
|
+
return new AstryxError(
|
|
217
|
+
`Icon set "${name}" can't ${current != null ? `move its default variant from "${current}" to "${looks.default}"` : `take "${looks.default}" as its default variant`} in place: each of its ${count} icons still draws "${now}". Wrap the library again with the new default, so each icon takes that look.`,
|
|
218
|
+
[
|
|
219
|
+
{
|
|
220
|
+
name: refreshCommand(name, module, looks),
|
|
221
|
+
reason: 'wrap the library again in the new default look',
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The refusal for a default variant that would move on a set whose
|
|
230
|
+
* library's export names name no looks. The icons' exports stay as they
|
|
231
|
+
* are on every path, so only another variant gives them another look.
|
|
232
|
+
* @param {string} name
|
|
233
|
+
* @param {number} count the set's icons
|
|
234
|
+
* @param {string} current the set's default variant
|
|
235
|
+
* @param {Looks} looks
|
|
236
|
+
*/
|
|
237
|
+
function unencodedMove(name, count, current, looks) {
|
|
238
|
+
const variants = [...new Set([current, ...looks.variants])];
|
|
239
|
+
return new AstryxError(
|
|
240
|
+
`Icon set "${name}" can't move its default variant from "${current}" to "${looks.default}": its icons' export names name no looks, so each of its ${count} icons draws "${current}", the look its icons' module draws. Keep "${current}" as the default, declare "${looks.default}" as a variant, and add it from the module that draws it (fill <module> with that module).`,
|
|
241
|
+
[
|
|
242
|
+
{
|
|
243
|
+
name: `astryx experimental icon new-set ${name} --variants ${variants.join(',')} --default-variant ${current}`,
|
|
244
|
+
reason: `declare ${looks.default} as a variant and keep ${current} as the default`,
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: `astryx experimental icon add --variant ${looks.default} --from <module> --all --set ${name}`,
|
|
248
|
+
reason: `give each icon its ${looks.default} look from the module that draws it`,
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The refusal for `--variants` that leave out the default variant of a set
|
|
257
|
+
* whose library's export names name no looks. Its icons keep their exports,
|
|
258
|
+
* so they still draw the default, and the set must keep declaring it.
|
|
259
|
+
* @param {string} name
|
|
260
|
+
* @param {number} count the set's icons
|
|
261
|
+
* @param {string} current the set's default variant
|
|
262
|
+
* @param {Looks} looks
|
|
263
|
+
* @param {string} from ` --from <module>` on a refresh, else empty
|
|
264
|
+
*/
|
|
265
|
+
function droppedDefault(name, count, current, looks, from) {
|
|
266
|
+
const others = looks.variants.filter(variant => variant !== current);
|
|
267
|
+
return new AstryxError(
|
|
268
|
+
`--variants (${looks.variants.join(', ')}) leaves out "${current}", the default variant of icon set "${name}". Its icons' export names name no looks, so each of its ${count} icons still draws "${current}", the look its icons' module draws. List "${current}" in --variants, and add each other look as a variant from the module that draws it (fill <module> with that module).`,
|
|
269
|
+
[
|
|
270
|
+
{
|
|
271
|
+
name: `astryx experimental icon new-set ${name}${from} --variants ${[current, ...others].join(',')}`,
|
|
272
|
+
reason: `keep ${current}, the look each icon draws, as the default`,
|
|
273
|
+
},
|
|
274
|
+
...others.map(variant => ({
|
|
275
|
+
name: `astryx experimental icon add --variant ${variant} --from <module> --all --set ${name}`,
|
|
276
|
+
reason: `give each icon its ${variant} look from the module that draws it`,
|
|
277
|
+
})),
|
|
278
|
+
],
|
|
279
|
+
ERROR_CODES.ERR_INVALID_OPTION,
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* The variants and default variant to write for a command that declares
|
|
285
|
+
* looks, and whether the set's icons must move to a new look. Every path
|
|
286
|
+
* that writes `default.variant` uses it:
|
|
287
|
+
*
|
|
288
|
+
* - The drawn look is read from every look word of the exports the set
|
|
289
|
+
* wraps (`drawn`), or, with no icons from the library yet, is the look
|
|
290
|
+
* the library is wrapped in by default.
|
|
291
|
+
* - A named default must be a look word the library has.
|
|
292
|
+
* - A named default other than the drawn look moves the icons only on a
|
|
293
|
+
* refresh (`library` given), where each glyph that has the look takes it;
|
|
294
|
+
* in place it is refused with the refresh command.
|
|
295
|
+
* - With none named, the default is the drawn look, which `--variants` must
|
|
296
|
+
* list.
|
|
297
|
+
*
|
|
298
|
+
* A library whose names encode no looks has no look words: there the named
|
|
299
|
+
* variant, the set's current default, or the first variant is the default.
|
|
300
|
+
* Its icons keep their exports on every path, so a set with icons keeps a
|
|
301
|
+
* declared default, `--variants` must list it, and with none declared the
|
|
302
|
+
* command names it.
|
|
303
|
+
* @param {object} args
|
|
304
|
+
* @param {string} args.name the set
|
|
305
|
+
* @param {Looks | null} args.given the variants and default the command names
|
|
306
|
+
* @param {string | undefined} args.current the set's `default.variant`
|
|
307
|
+
* @param {number} args.icons how many icons the set has
|
|
308
|
+
* @param {DrawnLooks | null} args.drawn what the set's icons draw now
|
|
309
|
+
* @param {{module: string, positions: Array<Set<string>>} | null} args.library
|
|
310
|
+
* the library `--from` wraps; null in place
|
|
311
|
+
* @returns {{looks: Looks | null, moved: boolean}}
|
|
312
|
+
*/
|
|
313
|
+
export function resolveDefaultLook({
|
|
314
|
+
name,
|
|
315
|
+
given,
|
|
316
|
+
current,
|
|
317
|
+
icons,
|
|
318
|
+
drawn,
|
|
319
|
+
library,
|
|
320
|
+
}) {
|
|
321
|
+
if (!given) return {looks: null, moved: false};
|
|
322
|
+
const refresh = library != null;
|
|
323
|
+
const positions =
|
|
324
|
+
library != null ? library.positions : (drawn?.positions ?? []);
|
|
325
|
+
const module = library?.module ?? drawn?.module;
|
|
326
|
+
const now = drawn != null && drawn.positions.length > 0 ? drawn : null;
|
|
327
|
+
if (positions.length === 0) {
|
|
328
|
+
return unencodedDefault({name, given, current, icons, module, refresh});
|
|
329
|
+
}
|
|
330
|
+
if (given.named) {
|
|
331
|
+
const chosen = given.default;
|
|
332
|
+
const index = positions.findIndex(position => position.has(chosen));
|
|
333
|
+
if (index < 0) {
|
|
334
|
+
throw unknownLook(
|
|
335
|
+
chosen,
|
|
336
|
+
'--default-variant',
|
|
337
|
+
/** @type {string} */ (module),
|
|
338
|
+
positions,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
const drawnHere = now?.words[index] ?? null;
|
|
342
|
+
if (now != null && drawnHere != null && drawnHere !== chosen) {
|
|
343
|
+
if (!refresh) {
|
|
344
|
+
throw inPlaceMove(name, now.icons, drawnHere, given, module, current);
|
|
345
|
+
}
|
|
346
|
+
return {looks: given, moved: true};
|
|
347
|
+
}
|
|
348
|
+
return {looks: given, moved: false};
|
|
349
|
+
}
|
|
350
|
+
const words = now != null ? now.words : preferredLook(positions, []);
|
|
351
|
+
const look = drawnWord(positions, words, given.variants);
|
|
352
|
+
if (look == null || !given.variants.includes(look)) {
|
|
353
|
+
const shown = look ?? '<look>';
|
|
354
|
+
throw new AstryxError(
|
|
355
|
+
`None of --variants (${given.variants.join(', ')}) is the look ${now != null ? `the set's ${now.icons} icons draw` : `${module} is wrapped in by default`} ("${shown}"), and each icon's own export draws the default variant. List it in --variants, or name the default with --default-variant.`,
|
|
356
|
+
[
|
|
357
|
+
{
|
|
358
|
+
name: `astryx experimental icon new-set ${name}${refresh ? ` --from ${shellArg(/** @type {string} */ (module))}` : ''} --variants ${[shown, ...given.variants].join(',')}`,
|
|
359
|
+
reason: `declare ${shown}, the look each icon draws, as the default`,
|
|
360
|
+
},
|
|
361
|
+
],
|
|
362
|
+
ERROR_CODES.ERR_INVALID_OPTION,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
return {looks: {...given, default: look}, moved: false};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* {@link resolveDefaultLook} for a library whose names encode no looks.
|
|
370
|
+
* @param {{name: string, given: Looks, current: string | undefined, icons: number, module: string | undefined, refresh: boolean}} args
|
|
371
|
+
* @returns {{looks: Looks, moved: boolean}}
|
|
372
|
+
*/
|
|
373
|
+
function unencodedDefault({name, given, current, icons, module, refresh}) {
|
|
374
|
+
if (given.named) {
|
|
375
|
+
if (current != null && given.default !== current && icons > 0) {
|
|
376
|
+
throw unencodedMove(name, icons, current, given);
|
|
377
|
+
}
|
|
378
|
+
return {looks: given, moved: false};
|
|
379
|
+
}
|
|
380
|
+
if (current != null && given.variants.includes(current)) {
|
|
381
|
+
return {looks: {...given, default: current}, moved: false};
|
|
382
|
+
}
|
|
383
|
+
const from = refresh && module ? ` --from ${shellArg(module)}` : '';
|
|
384
|
+
if (current != null && icons > 0) {
|
|
385
|
+
throw droppedDefault(name, icons, current, given, from);
|
|
386
|
+
}
|
|
387
|
+
if (current == null && icons > 0) {
|
|
388
|
+
throw new AstryxError(
|
|
389
|
+
`Icon set "${name}" declares no default variant, and its icons' export names name none of ${given.variants.join(', ')}. Name the look its ${icons} icons draw with --default-variant.`,
|
|
390
|
+
given.variants.map(variant => ({
|
|
391
|
+
name: `astryx experimental icon new-set ${name}${from} --variants ${given.variants.join(',')} --default-variant ${variant}`,
|
|
392
|
+
reason: `if each icon draws ${variant}`,
|
|
393
|
+
})),
|
|
394
|
+
ERROR_CODES.ERR_INVALID_OPTION,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
return {looks: given, moved: false};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* The default variant a command that declares `variant` beside the set's
|
|
402
|
+
* variants names: the set's own, else the look its icons draw.
|
|
403
|
+
* @param {LookSet} set
|
|
404
|
+
* @param {DrawnLooks | null} drawn
|
|
405
|
+
* @returns {string | null}
|
|
406
|
+
*/
|
|
407
|
+
function keptDefault(set, drawn) {
|
|
408
|
+
const current = set.data.default?.variant;
|
|
409
|
+
if (current) return current;
|
|
410
|
+
if (drawn == null || drawn.positions.length === 0) return null;
|
|
411
|
+
return drawnWord(drawn.positions, drawn.words, set.data.variants ?? []);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* The command that declares `variant` beside the set's variants. It names
|
|
416
|
+
* the default variant the set keeps, so it runs as printed.
|
|
417
|
+
* @param {LookSet} set
|
|
418
|
+
* @param {string} variant
|
|
419
|
+
* @param {DrawnLooks | null} drawn
|
|
420
|
+
* @returns {{name: string, reason: string}}
|
|
421
|
+
*/
|
|
422
|
+
export function declareVariantSuggestion(set, variant, drawn) {
|
|
423
|
+
const kept = keptDefault(set, drawn) ?? '<default>';
|
|
424
|
+
const declared = set.data.variants ?? [];
|
|
425
|
+
const variants = [
|
|
426
|
+
...new Set([
|
|
427
|
+
...(declared.includes(kept) ? [] : [kept]),
|
|
428
|
+
...declared,
|
|
429
|
+
variant,
|
|
430
|
+
]),
|
|
431
|
+
];
|
|
432
|
+
return {
|
|
433
|
+
name: `astryx experimental icon new-set ${set.name} --variants ${variants.join(',')} --default-variant ${kept}`,
|
|
434
|
+
reason:
|
|
435
|
+
kept === '<default>'
|
|
436
|
+
? 'declare the variants; fill <default> with the look the icons draw'
|
|
437
|
+
: 'declare the variants',
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Check that `add --variant` may add `variant` to the set's icons: a look
|
|
443
|
+
* word the library has, not the look each icon's own export draws (the
|
|
444
|
+
* default, declared or drawn), and declared by the set.
|
|
445
|
+
* @param {object} args
|
|
446
|
+
* @param {LookSet} args.set
|
|
447
|
+
* @param {string} args.variant
|
|
448
|
+
* @param {string} args.module the module the variant comes from
|
|
449
|
+
* @param {Array<Set<string>>} args.positions that module's look positions
|
|
450
|
+
* @param {DrawnLooks | null} args.drawn what the set's icons draw now
|
|
451
|
+
*/
|
|
452
|
+
export function checkVariantLook({set, variant, module, positions, drawn}) {
|
|
453
|
+
if (positions.length > 0 && !positions.some(each => each.has(variant))) {
|
|
454
|
+
throw unknownLook(variant, '--variant', module, positions);
|
|
455
|
+
}
|
|
456
|
+
const drawnPositions = drawn?.positions ?? [];
|
|
457
|
+
const index = drawnPositions.findIndex(each => each.has(variant));
|
|
458
|
+
const drawnHere = index >= 0 ? drawn?.words[index] : null;
|
|
459
|
+
if (set.data.default?.variant === variant || drawnHere === variant) {
|
|
460
|
+
throw new AstryxError(
|
|
461
|
+
`"${variant}" is the look each icon's own export in "${set.name}" already draws${set.data.default?.variant === variant ? ' (its default variant)' : ''}, so a variant of it would export the same artwork twice.`,
|
|
462
|
+
undefined,
|
|
463
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
const declared = set.data.variants ?? [];
|
|
467
|
+
if (!declared.includes(variant)) {
|
|
468
|
+
throw new AstryxError(
|
|
469
|
+
`Icon set "${set.name}" declares no variant "${variant}"${declared.length > 0 ? ` (it declares ${declared.join(', ')})` : ''}. Declare it first${keptDefault(set, drawn) == null ? ', and name the look its icons draw now as the default variant in place of <default>' : ''}.`,
|
|
470
|
+
[declareVariantSuggestion(set, variant, drawn)],
|
|
471
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
}
|
package/api/icon/_records.d.mts
CHANGED
|
@@ -63,4 +63,4 @@ export type IconSetIcon = import("../../authoring/doctypes/icon-set/type").IconS
|
|
|
63
63
|
export type IconRecord = import("./icon.type.mjs").IconRecord;
|
|
64
64
|
export type IconMatchEntry = import("./icon.type.mjs").IconMatchEntry;
|
|
65
65
|
import { AstryxError } from '../error.mjs';
|
|
66
|
-
export { iconRecord, importLine, leadingReading, matchIcon, rankIcons, scoreIcon } from "./_adapter.mjs";
|
|
66
|
+
export { answeringMatches, iconRecord, importLine, leadingReading, matchIcon, rankIcons, scoreIcon } from "./_adapter.mjs";
|
package/api/icon/_records.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import {AstryxError} from '../error.mjs';
|
|
|
15
15
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
16
16
|
import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
|
|
17
17
|
export {
|
|
18
|
+
answeringMatches,
|
|
18
19
|
iconRecord,
|
|
19
20
|
importLine,
|
|
20
21
|
leadingReading,
|