@trineui/cli 0.1.1 → 0.1.2
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 -0
- package/dist/add-component.js +53 -8
- package/dist/index.js +3 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ Notes:
|
|
|
31
31
|
- for `apps/demo`, `@trine/ui` resolves locally for delivered components while `@trine/ui/*` temporarily bridges non-localized components back to the authoring source
|
|
32
32
|
- the delivered shared styling baseline is `tokens.css` + `trine-consumer.css`
|
|
33
33
|
- the current proven target dependency baseline is Angular 21, Tailwind CSS v4, and `class-variance-authority`
|
|
34
|
+
- the current proven target shape accepts a global stylesheet entry such as `src/styles.scss`, `src/styles.css`, or `src/global.scss` when it is resolved from `angular.json`
|
|
34
35
|
- use a Node LTS line supported by Angular 21 in the target repo; odd-numbered Node releases can build with warnings
|
|
35
36
|
- when `package.json` is present in the target root, the CLI warns if Tailwind CSS v4 or `class-variance-authority` are missing
|
|
36
37
|
|
package/dist/add-component.js
CHANGED
|
@@ -61,10 +61,7 @@ const DEMO_PROXY_EXPORT_LINES = [
|
|
|
61
61
|
];
|
|
62
62
|
export function addComponent(manifest, options) {
|
|
63
63
|
const targetRoot = path.resolve(options.cwd, options.target);
|
|
64
|
-
const
|
|
65
|
-
const targetStylesEntry = path.join(targetRoot, 'src', 'styles.scss');
|
|
66
|
-
const targetTsconfig = path.join(targetRoot, 'tsconfig.app.json');
|
|
67
|
-
assertTargetShape(manifest.componentName, targetRoot, targetAppDir, targetStylesEntry, targetTsconfig);
|
|
64
|
+
const { targetStylesEntry, targetTsconfig } = resolveTargetShape(manifest.componentName, targetRoot);
|
|
68
65
|
const componentDestDir = path.join(targetRoot, 'src', 'app', 'components', 'ui', manifest.componentName);
|
|
69
66
|
const stylesDestDir = path.join(targetRoot, 'src', 'styles');
|
|
70
67
|
const componentCopyTargets = manifest.sourceFiles.map((source) => ({
|
|
@@ -146,7 +143,10 @@ function ensureSharedStyleBaseline(targetRoot, stylesDestDir, componentLabel) {
|
|
|
146
143
|
warnings,
|
|
147
144
|
};
|
|
148
145
|
}
|
|
149
|
-
function
|
|
146
|
+
function resolveTargetShape(componentName, targetRoot) {
|
|
147
|
+
const targetAppDir = path.join(targetRoot, 'src', 'app');
|
|
148
|
+
const targetTsconfig = path.join(targetRoot, 'tsconfig.app.json');
|
|
149
|
+
const targetStylesEntry = resolveStylesEntry(targetRoot);
|
|
150
150
|
const missing = [];
|
|
151
151
|
if (!existsSync(targetRoot)) {
|
|
152
152
|
missing.push(targetRoot);
|
|
@@ -154,18 +154,25 @@ function assertTargetShape(componentName, targetRoot, targetAppDir, targetStyles
|
|
|
154
154
|
if (!existsSync(targetAppDir)) {
|
|
155
155
|
missing.push(targetAppDir);
|
|
156
156
|
}
|
|
157
|
-
if (!
|
|
158
|
-
missing.push(
|
|
157
|
+
if (!targetStylesEntry) {
|
|
158
|
+
missing.push(`${path.join(targetRoot, 'src', 'styles.scss')} or ${path.join(targetRoot, 'src', 'styles.css')} or the first resolvable build styles entry in ${path.join(targetRoot, 'angular.json')}`);
|
|
159
159
|
}
|
|
160
160
|
if (!existsSync(targetTsconfig)) {
|
|
161
161
|
missing.push(targetTsconfig);
|
|
162
162
|
}
|
|
163
163
|
if (missing.length > 0) {
|
|
164
164
|
throw new Error([
|
|
165
|
-
`trine add ${componentName} requires an Angular app target with src/app,
|
|
165
|
+
`trine add ${componentName} requires an Angular app target with src/app, a global stylesheet entry, and tsconfig.app.json.`,
|
|
166
166
|
...missing.map((file) => `- ${file}`),
|
|
167
167
|
].join('\n'));
|
|
168
168
|
}
|
|
169
|
+
if (!targetStylesEntry) {
|
|
170
|
+
throw new Error(`trine add ${componentName} could not resolve a global stylesheet entry for ${targetRoot}.`);
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
targetStylesEntry,
|
|
174
|
+
targetTsconfig,
|
|
175
|
+
};
|
|
169
176
|
}
|
|
170
177
|
function ensureLinesFile(filePath, lines) {
|
|
171
178
|
const existing = existsSync(filePath) ? readFileSync(filePath, 'utf8') : '';
|
|
@@ -315,3 +322,41 @@ function readTargetDependencyWarnings(targetRoot, componentLabel) {
|
|
|
315
322
|
function looksLikeTailwindV4(range) {
|
|
316
323
|
return /(^|[^\d])4(\D|$)/.test(range);
|
|
317
324
|
}
|
|
325
|
+
export function looksLikeAngularAppRoot(root) {
|
|
326
|
+
return (existsSync(path.join(root, 'src', 'app')) &&
|
|
327
|
+
existsSync(path.join(root, 'tsconfig.app.json')) &&
|
|
328
|
+
resolveStylesEntry(root) !== undefined);
|
|
329
|
+
}
|
|
330
|
+
function resolveStylesEntry(targetRoot) {
|
|
331
|
+
const conventionalStyles = ['src/styles.scss', 'src/styles.css'];
|
|
332
|
+
for (const relativePath of conventionalStyles) {
|
|
333
|
+
const absolutePath = path.join(targetRoot, relativePath);
|
|
334
|
+
if (existsSync(absolutePath)) {
|
|
335
|
+
return absolutePath;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const angularJsonPath = path.join(targetRoot, 'angular.json');
|
|
339
|
+
if (!existsSync(angularJsonPath)) {
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
try {
|
|
343
|
+
const angularJson = JSON.parse(readFileSync(angularJsonPath, 'utf8'));
|
|
344
|
+
for (const project of Object.values(angularJson.projects ?? {})) {
|
|
345
|
+
const styles = project.architect?.build?.options?.styles ?? project.targets?.build?.options?.styles ?? [];
|
|
346
|
+
for (const styleEntry of styles) {
|
|
347
|
+
const relativePath = typeof styleEntry === 'string' ? styleEntry : (styleEntry.input ?? undefined);
|
|
348
|
+
if (!relativePath) {
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
const absolutePath = path.join(targetRoot, relativePath);
|
|
352
|
+
if (existsSync(absolutePath)) {
|
|
353
|
+
return absolutePath;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
return undefined;
|
|
360
|
+
}
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { readdirSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { looksLikeAngularAppRoot } from "./add-component.js";
|
|
4
5
|
import { addButton } from "./add-button.js";
|
|
5
6
|
const HELP_TEXT = `Usage:
|
|
6
7
|
npx @trineui/cli@latest add button [--target <app-root>]
|
|
@@ -14,7 +15,7 @@ Defaults:
|
|
|
14
15
|
Notes:
|
|
15
16
|
- v0 supports Button only
|
|
16
17
|
- external targets can run trine add button from the app root or pass --target /absolute/path/to/angular-app
|
|
17
|
-
- the current proven target model is Angular 21 + src/app + src/styles.scss
|
|
18
|
+
- the current proven target model is Angular 21 + src/app + tsconfig.app.json + a global stylesheet entry such as src/styles.scss, src/styles.css, or src/global.scss resolved from angular.json
|
|
18
19
|
- use a Node LTS line supported by Angular 21 in the target repo
|
|
19
20
|
- the current proven styling/runtime baseline requires Tailwind CSS v4 and class-variance-authority in the target repo
|
|
20
21
|
- consumer-owned component files fail clearly if they already exist
|
|
@@ -75,9 +76,6 @@ function isSupportedComponent(value) {
|
|
|
75
76
|
function capitalize(value) {
|
|
76
77
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
77
78
|
}
|
|
78
|
-
function looksLikeAngularAppRoot(root) {
|
|
79
|
-
return ['src/app', 'src/styles.scss', 'tsconfig.app.json'].every((relativePath) => existsSync(path.join(root, relativePath)));
|
|
80
|
-
}
|
|
81
79
|
function autoDetectTarget(cwd) {
|
|
82
80
|
if (looksLikeAngularAppRoot(cwd)) {
|
|
83
81
|
return '.';
|