@santi020k/lumen 0.1.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/LICENSE +21 -0
- package/README.md +33 -0
- package/bin/lumen.mjs +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +136 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/installer.d.ts +26 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +181 -0
- package/dist/registry-data.d.ts +871 -0
- package/dist/registry-data.d.ts.map +1 -0
- package/dist/registry-data.js +1704 -0
- package/dist/registry-types.d.ts +33 -0
- package/dist/registry-types.d.ts.map +1 -0
- package/dist/registry-types.js +1 -0
- package/dist/registry.d.ts +9 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +89 -0
- package/package.json +73 -0
- package/styles.css +5570 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Santiago Molina
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @santi020k/lumen
|
|
2
|
+
|
|
3
|
+
Shared foundation and umbrella package for Lumen UI.
|
|
4
|
+
|
|
5
|
+
Install the framework package directly:
|
|
6
|
+
|
|
7
|
+
- `@santi020k/lumen-astro`
|
|
8
|
+
- `@santi020k/lumen-react`
|
|
9
|
+
- `@santi020k/lumen-elements`
|
|
10
|
+
|
|
11
|
+
Each adapter includes the shared foundation and exposes its own stylesheet entry. Install this
|
|
12
|
+
umbrella package only when you want the framework-neutral CLI or registry APIs:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add @santi020k/lumen
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The umbrella package also exposes typed registry metadata and the `lumen` CLI:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
lumen list
|
|
22
|
+
lumen show Button
|
|
23
|
+
lumen add Button
|
|
24
|
+
lumen add Button --target react
|
|
25
|
+
lumen add Button --target elements
|
|
26
|
+
lumen add scheduler
|
|
27
|
+
lumen add scheduler --target react
|
|
28
|
+
lumen add scheduler --target elements
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Use `lumen add <component>` for a local Astro wrapper, `--target react` for a React wrapper, or
|
|
32
|
+
`--target elements` for a custom-elements starter. Bundled recipes support the same Astro, React,
|
|
33
|
+
and Elements targets.
|
package/bin/lumen.mjs
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { addLumenRegistryItem, getLumenRegistryEntries, getLumenRegistryItem, loadLumenRegistry, lumenRegistry } from './registry.js';
|
|
2
|
+
const args = process.argv.slice(2);
|
|
3
|
+
const [command = 'help', name] = args;
|
|
4
|
+
const dryRun = args.includes('--dry-run');
|
|
5
|
+
const failOnConflict = args.includes('--fail-on-conflict');
|
|
6
|
+
const force = args.includes('--force');
|
|
7
|
+
const merge = args.includes('--merge');
|
|
8
|
+
const cwdIndex = args.indexOf('--cwd');
|
|
9
|
+
const cwd = cwdIndex >= 0 ? args[cwdIndex + 1] : undefined;
|
|
10
|
+
const registryIndex = args.indexOf('--registry');
|
|
11
|
+
const registrySource = registryIndex >= 0 ? args[registryIndex + 1] : undefined;
|
|
12
|
+
const registryTokenIndex = args.indexOf('--registry-token');
|
|
13
|
+
const registryToken = registryTokenIndex >= 0 ? args[registryTokenIndex + 1] : process.env.LUMEN_REGISTRY_TOKEN;
|
|
14
|
+
const targetIndex = args.indexOf('--target');
|
|
15
|
+
const targetProvided = targetIndex >= 0;
|
|
16
|
+
const targetValue = targetIndex >= 0 ? args[targetIndex + 1] : undefined;
|
|
17
|
+
let conflict = 'skip';
|
|
18
|
+
const getAddTarget = (value, provided = false) => {
|
|
19
|
+
if (provided && !value) {
|
|
20
|
+
throw new Error('Missing Lumen add target. Use astro, react, or elements.');
|
|
21
|
+
}
|
|
22
|
+
if (!value || value === 'astro')
|
|
23
|
+
return 'astro';
|
|
24
|
+
if (value === 'react' || value === 'elements')
|
|
25
|
+
return value;
|
|
26
|
+
throw new Error(`Unknown Lumen add target: ${value}. Use astro, react, or elements.`);
|
|
27
|
+
};
|
|
28
|
+
if (failOnConflict) {
|
|
29
|
+
conflict = 'error';
|
|
30
|
+
}
|
|
31
|
+
else if (merge) {
|
|
32
|
+
conflict = 'merge';
|
|
33
|
+
}
|
|
34
|
+
const formatList = (registry = lumenRegistry) => getLumenRegistryEntries(registry)
|
|
35
|
+
.map(item => `${item.name} (${item.type})`)
|
|
36
|
+
.join('\n');
|
|
37
|
+
const getRegistryFilePath = (file) => typeof file === 'string' ? file : file.path;
|
|
38
|
+
const getRegistryItemFiles = (item) => {
|
|
39
|
+
if (!item.files?.length)
|
|
40
|
+
return undefined;
|
|
41
|
+
return item.files.map(getRegistryFilePath).join(', ');
|
|
42
|
+
};
|
|
43
|
+
const getRegistryItemDescription = (item) => 'description' in item ? item.description : undefined;
|
|
44
|
+
const getRegistryItemCategory = (item) => 'category' in item ? `category: ${item.category}` : undefined;
|
|
45
|
+
const getRegistryItemComponents = (item) => 'components' in item && Array.isArray(item.components) && item.components.length > 0
|
|
46
|
+
? `components: ${item.components.join(', ')}`
|
|
47
|
+
: undefined;
|
|
48
|
+
const getRegistryItemDependencies = (item) => 'dependencies' in item && item.dependencies.length > 0
|
|
49
|
+
? `dependencies: ${item.dependencies.join(', ')}`
|
|
50
|
+
: undefined;
|
|
51
|
+
const formatItem = (itemName, registry = lumenRegistry) => {
|
|
52
|
+
const item = getLumenRegistryItem(itemName, registry);
|
|
53
|
+
if (!item) {
|
|
54
|
+
process.exitCode = 1;
|
|
55
|
+
return `Unknown Lumen registry item: ${itemName}`;
|
|
56
|
+
}
|
|
57
|
+
const lines = [
|
|
58
|
+
`${item.name} (${item.type})`,
|
|
59
|
+
getRegistryItemDescription(item),
|
|
60
|
+
getRegistryItemCategory(item),
|
|
61
|
+
getRegistryItemComponents(item),
|
|
62
|
+
getRegistryItemDependencies(item)
|
|
63
|
+
];
|
|
64
|
+
const files = getRegistryItemFiles(item);
|
|
65
|
+
if (files) {
|
|
66
|
+
lines.push(`files: ${files}`);
|
|
67
|
+
}
|
|
68
|
+
return lines.filter((line) => Boolean(line)).join('\n');
|
|
69
|
+
};
|
|
70
|
+
const formatAddResult = async (itemName, registry) => {
|
|
71
|
+
const result = await addLumenRegistryItem(itemName, {
|
|
72
|
+
...(cwd ? { cwd } : {}),
|
|
73
|
+
conflict,
|
|
74
|
+
dryRun,
|
|
75
|
+
force,
|
|
76
|
+
registry,
|
|
77
|
+
target: getAddTarget(targetValue, targetProvided)
|
|
78
|
+
});
|
|
79
|
+
return [
|
|
80
|
+
`${result.dryRun ? 'Would add' : 'Added'} ${result.item.name}`,
|
|
81
|
+
...result.added.map(file => `- ${file}`),
|
|
82
|
+
...result.merged.map(file => `- merged existing ${file}`),
|
|
83
|
+
...result.skipped.map(file => `- skipped existing ${file}`)
|
|
84
|
+
].join('\n');
|
|
85
|
+
};
|
|
86
|
+
const help = [
|
|
87
|
+
'Lumen registry helper',
|
|
88
|
+
'',
|
|
89
|
+
'Commands:',
|
|
90
|
+
' lumen list List registry items',
|
|
91
|
+
' lumen show <name> Show components and files for an item',
|
|
92
|
+
' lumen add <name> Install a recipe or component into the current project',
|
|
93
|
+
' lumen install Print install commands',
|
|
94
|
+
'',
|
|
95
|
+
'Options:',
|
|
96
|
+
' --cwd <path> Target directory for lumen add',
|
|
97
|
+
' --dry-run Print files without writing them',
|
|
98
|
+
' --fail-on-conflict Exit if a target recipe file already exists',
|
|
99
|
+
' --force Overwrite existing recipe files',
|
|
100
|
+
' --merge Merge recipe files with existing files',
|
|
101
|
+
' --registry <source> Load list/show data from a local or remote registry JSON file',
|
|
102
|
+
' --registry-token <key> Use a bearer token for private remote registries',
|
|
103
|
+
' --target <framework> Generate wrappers or recipe starters for astro, react, or elements',
|
|
104
|
+
''
|
|
105
|
+
].join('\n');
|
|
106
|
+
const run = async () => {
|
|
107
|
+
let output = help;
|
|
108
|
+
const registry = registrySource
|
|
109
|
+
? await loadLumenRegistry(registrySource, registryToken ? { token: registryToken } : {})
|
|
110
|
+
: lumenRegistry;
|
|
111
|
+
switch (command) {
|
|
112
|
+
case 'add': {
|
|
113
|
+
if (name)
|
|
114
|
+
output = await formatAddResult(name, registry);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case 'install': {
|
|
118
|
+
output = 'pnpm add @santi020k/lumen-astro\nnpm install @santi020k/lumen-astro\nyarn add @santi020k/lumen-astro';
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case 'list': {
|
|
122
|
+
output = formatList(registry);
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case 'show': {
|
|
126
|
+
if (name)
|
|
127
|
+
output = formatItem(name, registry);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
process.stdout.write(`${output}\n`);
|
|
132
|
+
};
|
|
133
|
+
run().catch((error) => {
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
136
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { addLumenRegistryItem, getLumenRegistryEntries, getLumenRegistryItem, loadLumenRegistry, type LumenAddOptions, type LumenAddResult, type LumenAddTarget, type LumenMergeConflict, type LumenRegistry, lumenRegistry, type LumenRegistryComponent, type LumenRegistryEntry, type LumenRegistryFile, type LumenRegistryItem, type LumenRegistryLoadOptions } from './registry.js';
|
|
2
|
+
export { applyDataViewState, canPlaceScheduleEvent, coerceThemeBuilderExportFormat, coerceThemeBuilderMode, coerceThemeBuilderScheme, composeClassName, createDataViewRequestUrl, createDataViewSearchParams, createDataViewServerRequest, createDataViewState, createDataViewStorageKey, createScheduleSlots, createScheduleStorageKey, createThemeBuilderTokens, createThemePalette, expandRecurringScheduleEvent, exportThemeBuilderCss, exportThemeBuilderValue, exportThemeCss, filterDataRecords, getContrastRatio, getScheduleConflicts, getVirtualRange, loadDataViewState, loadScheduleEvents, type LumenCodeToken, lumenCodeTokenClassNames, type LumenCodeTokenKind, lumenColors, type LumenColorTokenName, lumenColorTokenNames, type LumenComponentName, lumenComponentNames, type LumenContrastScore, lumenDarkTheme, type LumenDataRecord, type LumenDataViewServerRequest, type LumenDataViewState, lumenGlass, type LumenGlassColorTokenName, lumenGlassColorTokenNames, type LumenGlassEffectTokenName, lumenGlassEffectTokenNames, type LumenGlassTokenName, lumenGlassTokenNames, type LumenKeyValueReader, type LumenKeyValueStorage, type LumenKeyValueWriter, lumenLightTheme, lumenPackages, type LumenPackageTarget, type LumenScheduleConflict, type LumenScheduleEvent, type LumenScheduleKeyValueReader, type LumenScheduleKeyValueStorage, type LumenScheduleKeyValueWriter, type LumenScheduleResizeEdge, type LumenScheduleResizeOptions, type LumenScheduleResource, type LumenScheduleSlot, type LumenSemanticColorTokenName, lumenSemanticColorTokenNames, type LumenSortDirection, lumenThemeAttribute, type LumenThemeBuilderExportFormat, type LumenThemeBuilderMode, type LumenThemeBuilderOptions, type LumenThemeBuilderResult, type LumenThemeBuilderScheme, type LumenThemeContrastSuggestion, type LumenThemeTokens, lumenTokenNames, mergeThemeTokens, moveScheduleEvent, normalizeLumenCode, normalizeThemeBuilderHex, normalizeThemeBuilderHue, paginateDataRecords, parseDataViewState, parseScheduleEvents, parseThemeCss, pinDataViewColumn, renderLumenCodeHtml, resizeScheduleEvent, resizeScheduleEvents, saveDataViewState, saveScheduleEvents, scheduleEventsOverlap, scoreThemeContrast, serializeDataViewState, serializeScheduleEvents, sortDataRecords, suggestReadableInk, themeBuilderHexToHsl, toggleDataViewSelection, tokenizeLumenCode, tuneThemeContrast, unpinDataViewColumn } from '@santi020k/lumen-core';
|
|
3
|
+
export declare const lumen: {
|
|
4
|
+
readonly name: "Lumen";
|
|
5
|
+
readonly packageName: "@santi020k/lumen";
|
|
6
|
+
readonly scope: "@santi020k";
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,aAAa,EACb,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC9B,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,8BAA8B,EAC9B,sBAAsB,EACtB,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,4BAA4B,EAC5B,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,cAAc,EACnB,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,WAAW,EACX,KAAK,mBAAmB,EACxB,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,UAAU,EACV,KAAK,wBAAwB,EAC7B,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,0BAA0B,EAC1B,KAAK,mBAAmB,EACxB,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,eAAe,EACf,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,4BAA4B,EAC5B,KAAK,kBAAkB,EACvB,mBAAmB,EACnB,KAAK,6BAA6B,EAClC,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACjC,KAAK,gBAAgB,EACrB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,uBAAuB,CAAA;AAE9B,eAAO,MAAM,KAAK;;;;CAIR,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { addLumenRegistryItem, getLumenRegistryEntries, getLumenRegistryItem, loadLumenRegistry, lumenRegistry } from './registry.js';
|
|
2
|
+
export { applyDataViewState, canPlaceScheduleEvent, coerceThemeBuilderExportFormat, coerceThemeBuilderMode, coerceThemeBuilderScheme, composeClassName, createDataViewRequestUrl, createDataViewSearchParams, createDataViewServerRequest, createDataViewState, createDataViewStorageKey, createScheduleSlots, createScheduleStorageKey, createThemeBuilderTokens, createThemePalette, expandRecurringScheduleEvent, exportThemeBuilderCss, exportThemeBuilderValue, exportThemeCss, filterDataRecords, getContrastRatio, getScheduleConflicts, getVirtualRange, loadDataViewState, loadScheduleEvents, lumenCodeTokenClassNames, lumenColors, lumenColorTokenNames, lumenComponentNames, lumenDarkTheme, lumenGlass, lumenGlassColorTokenNames, lumenGlassEffectTokenNames, lumenGlassTokenNames, lumenLightTheme, lumenPackages, lumenSemanticColorTokenNames, lumenThemeAttribute, lumenTokenNames, mergeThemeTokens, moveScheduleEvent, normalizeLumenCode, normalizeThemeBuilderHex, normalizeThemeBuilderHue, paginateDataRecords, parseDataViewState, parseScheduleEvents, parseThemeCss, pinDataViewColumn, renderLumenCodeHtml, resizeScheduleEvent, resizeScheduleEvents, saveDataViewState, saveScheduleEvents, scheduleEventsOverlap, scoreThemeContrast, serializeDataViewState, serializeScheduleEvents, sortDataRecords, suggestReadableInk, themeBuilderHexToHsl, toggleDataViewSelection, tokenizeLumenCode, tuneThemeContrast, unpinDataViewColumn } from '@santi020k/lumen-core';
|
|
3
|
+
export const lumen = {
|
|
4
|
+
name: 'Lumen',
|
|
5
|
+
packageName: '@santi020k/lumen',
|
|
6
|
+
scope: '@santi020k'
|
|
7
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type LumenRegistry, type LumenRegistryEntry } from './registry.js';
|
|
2
|
+
export interface LumenAddOptions {
|
|
3
|
+
conflict?: 'error' | 'merge' | 'overwrite' | 'skip';
|
|
4
|
+
cwd?: string;
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
force?: boolean;
|
|
7
|
+
merge?: (conflict: LumenMergeConflict) => string;
|
|
8
|
+
registry?: LumenRegistry;
|
|
9
|
+
target?: LumenAddTarget;
|
|
10
|
+
}
|
|
11
|
+
export type LumenAddTarget = 'astro' | 'elements' | 'react';
|
|
12
|
+
export interface LumenMergeConflict {
|
|
13
|
+
existing: string;
|
|
14
|
+
incoming: string;
|
|
15
|
+
path: string;
|
|
16
|
+
}
|
|
17
|
+
export interface LumenAddResult {
|
|
18
|
+
added: string[];
|
|
19
|
+
dryRun: boolean;
|
|
20
|
+
files: string[];
|
|
21
|
+
item: LumenRegistryEntry;
|
|
22
|
+
merged: string[];
|
|
23
|
+
skipped: string[];
|
|
24
|
+
}
|
|
25
|
+
export declare const addLumenRegistryItem: (name: string, options?: LumenAddOptions) => Promise<LumenAddResult>;
|
|
26
|
+
//# sourceMappingURL=installer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,kBAAkB,EAExB,MAAM,eAAe,CAAA;AAOtB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,CAAA;IACnD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,MAAM,CAAA;IAChD,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAA;AAE3D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,IAAI,EAAE,kBAAkB,CAAA;IACxB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AA4MD,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,UAAS,eAAoB,KAC5B,OAAO,CAAC,cAAc,CA2CxB,CAAA"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { access, mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join, relative, sep } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { getLumenRegistryItem, } from './registry.js';
|
|
5
|
+
const templatesRoot = fileURLToPath(new URL('../templates/', import.meta.url));
|
|
6
|
+
const loadRecipeTemplateFiles = async (itemName, target) => {
|
|
7
|
+
const templateDir = join(templatesRoot, target, itemName);
|
|
8
|
+
let entries;
|
|
9
|
+
try {
|
|
10
|
+
entries = await readdir(templateDir, { recursive: true, withFileTypes: true });
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const files = await Promise.all(entries
|
|
16
|
+
.filter(entry => entry.isFile())
|
|
17
|
+
.map(async (entry) => {
|
|
18
|
+
const absolutePath = join(entry.parentPath, entry.name);
|
|
19
|
+
return {
|
|
20
|
+
path: relative(templateDir, absolutePath).split(sep).join('/'),
|
|
21
|
+
source: await readFile(absolutePath, 'utf8')
|
|
22
|
+
};
|
|
23
|
+
}));
|
|
24
|
+
files.sort((first, second) => first.path.localeCompare(second.path));
|
|
25
|
+
return files.length > 0 ? files : undefined;
|
|
26
|
+
};
|
|
27
|
+
const toKebabCase = (name) => name.replaceAll(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
28
|
+
const toCamelCase = (value) => value.replaceAll(/-([a-z])/g, (_match, character) => character.toUpperCase());
|
|
29
|
+
const createAstroComponentFile = (name) => ({
|
|
30
|
+
path: `src/lumen/${toKebabCase(name)}.astro`,
|
|
31
|
+
source: `---
|
|
32
|
+
import { ${name} as Lumen${name} } from '@santi020k/lumen-astro'
|
|
33
|
+
|
|
34
|
+
const props = Astro.props
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
<Lumen${name} {...props}>
|
|
38
|
+
<slot />
|
|
39
|
+
</Lumen${name}>
|
|
40
|
+
`
|
|
41
|
+
});
|
|
42
|
+
const createReactComponentFile = (name) => ({
|
|
43
|
+
path: `src/lumen/${toKebabCase(name)}.tsx`,
|
|
44
|
+
source: `import type { ComponentPropsWithoutRef } from 'react'
|
|
45
|
+
|
|
46
|
+
import { ${name} as Lumen${name} } from '@santi020k/lumen-react'
|
|
47
|
+
|
|
48
|
+
export type ${name}Props = ComponentPropsWithoutRef<typeof Lumen${name}>
|
|
49
|
+
|
|
50
|
+
export const ${name} = (props: ${name}Props) => <Lumen${name} {...props} />
|
|
51
|
+
`
|
|
52
|
+
});
|
|
53
|
+
const createElementsComponentFile = (name) => {
|
|
54
|
+
const tagName = `lumen-${toKebabCase(name)}`;
|
|
55
|
+
const variableName = `${toCamelCase(toKebabCase(name))}TagName`;
|
|
56
|
+
return {
|
|
57
|
+
path: `src/lumen/${toKebabCase(name)}.ts`,
|
|
58
|
+
source: `import {
|
|
59
|
+
defineLumenElements,
|
|
60
|
+
Lumen${name}Element
|
|
61
|
+
} from '@santi020k/lumen-elements'
|
|
62
|
+
|
|
63
|
+
defineLumenElements()
|
|
64
|
+
|
|
65
|
+
export { Lumen${name}Element }
|
|
66
|
+
|
|
67
|
+
export const ${variableName} = '${tagName}' as const
|
|
68
|
+
|
|
69
|
+
declare global {
|
|
70
|
+
interface HTMLElementTagNameMap {
|
|
71
|
+
'${tagName}': InstanceType<typeof Lumen${name}Element>
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
`
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const createComponentFile = (name, target) => {
|
|
78
|
+
if (target === 'react')
|
|
79
|
+
return createReactComponentFile(name);
|
|
80
|
+
if (target === 'elements')
|
|
81
|
+
return createElementsComponentFile(name);
|
|
82
|
+
return createAstroComponentFile(name);
|
|
83
|
+
};
|
|
84
|
+
const getFilesForItem = async (item, target) => {
|
|
85
|
+
if (item.type === 'component')
|
|
86
|
+
return [createComponentFile(item.name, target)];
|
|
87
|
+
const targetRecipeFiles = await loadRecipeTemplateFiles(item.name, target);
|
|
88
|
+
if (targetRecipeFiles) {
|
|
89
|
+
return targetRecipeFiles;
|
|
90
|
+
}
|
|
91
|
+
const inlineFiles = item.files
|
|
92
|
+
?.filter((file) => typeof file !== 'string')
|
|
93
|
+
.map(file => ({
|
|
94
|
+
path: file.path,
|
|
95
|
+
source: file.source
|
|
96
|
+
})) ?? [];
|
|
97
|
+
if (inlineFiles.length > 0)
|
|
98
|
+
return inlineFiles;
|
|
99
|
+
if (item.type === 'recipe') {
|
|
100
|
+
throw new Error(`Registry recipe "${item.name}" does not have ${target} starter files yet.`);
|
|
101
|
+
}
|
|
102
|
+
return [];
|
|
103
|
+
};
|
|
104
|
+
const fileExists = async (path) => {
|
|
105
|
+
try {
|
|
106
|
+
await access(path);
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const mergeFileSource = ({ existing, incoming, path }) => {
|
|
114
|
+
if (existing.includes(incoming.trim()))
|
|
115
|
+
return existing;
|
|
116
|
+
return `${existing.trimEnd()}\n\n/* Lumen merge: ${path} */\n${incoming}`;
|
|
117
|
+
};
|
|
118
|
+
const getConflictMode = (options) => options.force ? 'overwrite' : options.conflict ?? 'skip';
|
|
119
|
+
const getInstallSource = async (file, target, exists, options, conflict) => {
|
|
120
|
+
if (!exists || conflict !== 'merge')
|
|
121
|
+
return file.source;
|
|
122
|
+
return (options.merge ?? mergeFileSource)({
|
|
123
|
+
existing: await readFile(target, 'utf8'),
|
|
124
|
+
incoming: file.source,
|
|
125
|
+
path: file.path
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
const writeInstallFile = async (target, source, dryRun) => {
|
|
129
|
+
if (dryRun)
|
|
130
|
+
return;
|
|
131
|
+
await mkdir(dirname(target), { recursive: true });
|
|
132
|
+
await writeFile(target, source, 'utf8');
|
|
133
|
+
};
|
|
134
|
+
const installRegistryFile = async (file, cwd, options, conflict) => {
|
|
135
|
+
const target = join(cwd, file.path);
|
|
136
|
+
const exists = await fileExists(target);
|
|
137
|
+
if (exists && conflict === 'error') {
|
|
138
|
+
throw new Error(`Refusing to overwrite existing file: ${file.path}`);
|
|
139
|
+
}
|
|
140
|
+
if (exists && conflict === 'skip')
|
|
141
|
+
return 'skipped';
|
|
142
|
+
const source = await getInstallSource(file, target, exists, options, conflict);
|
|
143
|
+
await writeInstallFile(target, source, options.dryRun);
|
|
144
|
+
return exists && conflict === 'merge' ? 'merged' : 'added';
|
|
145
|
+
};
|
|
146
|
+
export const addLumenRegistryItem = async (name, options = {}) => {
|
|
147
|
+
const item = getLumenRegistryItem(name, options.registry);
|
|
148
|
+
if (!item) {
|
|
149
|
+
throw new Error(`Unknown Lumen registry item: ${name}`);
|
|
150
|
+
}
|
|
151
|
+
const files = await getFilesForItem(item, options.target ?? 'astro');
|
|
152
|
+
const cwd = options.cwd ?? process.cwd();
|
|
153
|
+
if (!files.length) {
|
|
154
|
+
throw new Error(`Registry item cannot be installed yet: ${name}`);
|
|
155
|
+
}
|
|
156
|
+
const added = [];
|
|
157
|
+
const conflict = getConflictMode(options);
|
|
158
|
+
const merged = [];
|
|
159
|
+
const skipped = [];
|
|
160
|
+
for (const file of files) {
|
|
161
|
+
const outcome = await installRegistryFile(file, cwd, options, conflict);
|
|
162
|
+
if (outcome === 'skipped') {
|
|
163
|
+
skipped.push(file.path);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (outcome === 'merged') {
|
|
167
|
+
merged.push(file.path);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
added.push(file.path);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
added,
|
|
175
|
+
dryRun: Boolean(options.dryRun),
|
|
176
|
+
files: files.map(file => file.path),
|
|
177
|
+
item,
|
|
178
|
+
merged,
|
|
179
|
+
skipped
|
|
180
|
+
};
|
|
181
|
+
};
|