@nooeh/cli 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/add.js +8 -14
- package/dist/arguments.d.ts +2 -1
- package/dist/config.d.ts +3 -5
- package/dist/config.js +55 -53
- package/dist/doctor.js +42 -49
- package/dist/index.js +1 -1
- package/dist/init.js +36 -56
- package/dist/new-component.js +4 -11
- package/package.json +2 -2
package/dist/add.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { dirname, isAbsolute, join, relative, resolve
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
3
|
import { createInterface } from "node:readline/promises";
|
|
4
|
-
import { defaultConfig, hasConfig, readConfig,
|
|
4
|
+
import { defaultConfig, hasConfig, readConfig, resolveConfigAlias } from "./config.js";
|
|
5
5
|
import { installDependencies } from "./dependencies.js";
|
|
6
6
|
import { init } from "./init.js";
|
|
7
7
|
import { resolveComponent } from "./registry.js";
|
|
@@ -49,14 +49,8 @@ function resolveTargetPath(uiDirectory, filePath) {
|
|
|
49
49
|
}
|
|
50
50
|
return targetPath;
|
|
51
51
|
}
|
|
52
|
-
function replaceTokenImport(source,
|
|
53
|
-
|
|
54
|
-
const relativePath = relative(dirname(targetPath), tokenModulePath)
|
|
55
|
-
.replace(/\.ts$/, "")
|
|
56
|
-
.split(sep)
|
|
57
|
-
.join("/");
|
|
58
|
-
const tokenModule = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
59
|
-
return source.replaceAll("@nooeh/tokens/tokens.stylex", tokenModule);
|
|
52
|
+
function replaceTokenImport(source, stylesAlias) {
|
|
53
|
+
return source.replaceAll("@nooeh/tokens/semantic.stylex", `${stylesAlias}/semantic.stylex`);
|
|
60
54
|
}
|
|
61
55
|
export async function add(projectDirectory, componentName, options = {}) {
|
|
62
56
|
if (!componentName)
|
|
@@ -70,8 +64,7 @@ export async function add(projectDirectory, componentName, options = {}) {
|
|
|
70
64
|
}
|
|
71
65
|
const config = options["dry-run"] && shouldInitialize ? defaultConfig : await readConfig(projectDirectory);
|
|
72
66
|
const resolved = await resolveComponent(componentName);
|
|
73
|
-
const uiDirectory = await
|
|
74
|
-
const tokenDirectory = resolveTokensPath(projectDirectory, config.tokens);
|
|
67
|
+
const uiDirectory = await resolveConfigAlias(projectDirectory, config.aliases.ui, "aliases.ui");
|
|
75
68
|
let isOverwriteConfirmed = false;
|
|
76
69
|
async function confirmOverwrite() {
|
|
77
70
|
if (isOverwriteConfirmed)
|
|
@@ -85,7 +78,7 @@ export async function add(projectDirectory, componentName, options = {}) {
|
|
|
85
78
|
console.log(`Will add: ${targetPath}`);
|
|
86
79
|
continue;
|
|
87
80
|
}
|
|
88
|
-
await writeSource(replaceTokenImport(file.content,
|
|
81
|
+
await writeSource(replaceTokenImport(file.content, config.aliases.styles), targetPath, confirmOverwrite);
|
|
89
82
|
}
|
|
90
83
|
const shouldInstallDependencies = resolved.externalDependencies.length > 0 &&
|
|
91
84
|
!options.skipDependencyInstall &&
|
|
@@ -101,5 +94,6 @@ export async function add(projectDirectory, componentName, options = {}) {
|
|
|
101
94
|
return;
|
|
102
95
|
}
|
|
103
96
|
console.log(`Added ${componentName}.`);
|
|
104
|
-
console.log(`
|
|
97
|
+
console.log(`Export: ${primaryExport}`);
|
|
98
|
+
console.log(`Location: ${relative(projectDirectory, join(uiDirectory, `${componentName}.tsx`))}`);
|
|
105
99
|
}
|
package/dist/arguments.d.ts
CHANGED
|
@@ -5,8 +5,9 @@ export type CliOptions = Record<string, boolean | string | undefined> & {
|
|
|
5
5
|
"dry-run"?: boolean;
|
|
6
6
|
force?: boolean;
|
|
7
7
|
"skip-dependencies"?: boolean;
|
|
8
|
+
styles?: string;
|
|
8
9
|
tokens?: string;
|
|
9
|
-
|
|
10
|
+
ui?: string;
|
|
10
11
|
};
|
|
11
12
|
export declare function parseArguments(arguments_: readonly string[]): {
|
|
12
13
|
command: string;
|
package/dist/config.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
export declare const configFileName = "nooeh.json";
|
|
2
|
-
export declare const configVersion = 2;
|
|
3
2
|
export type NooehConfig = {
|
|
4
3
|
aliases: {
|
|
5
4
|
ui: string;
|
|
5
|
+
styles: string;
|
|
6
6
|
};
|
|
7
|
-
tokens: string;
|
|
8
|
-
version?: number;
|
|
9
7
|
};
|
|
10
8
|
export declare const defaultConfig: NooehConfig;
|
|
11
9
|
export declare function hasConfig(projectDirectory: string): Promise<boolean>;
|
|
12
10
|
export declare function validateConfig(config: unknown): NooehConfig;
|
|
13
11
|
export declare function readConfig(projectDirectory: string): Promise<NooehConfig>;
|
|
14
12
|
export declare function writeConfig(projectDirectory: string, config: NooehConfig): Promise<string>;
|
|
15
|
-
export declare function
|
|
16
|
-
export declare function
|
|
13
|
+
export declare function resolveConfigPath(projectDirectory: string, path: string, name: string): string;
|
|
14
|
+
export declare function resolveConfigAlias(projectDirectory: string, alias: string, name: string): Promise<string>;
|
package/dist/config.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { access, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { isAbsolute, relative, resolve } from "node:path";
|
|
2
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
3
3
|
export const configFileName = "nooeh.json";
|
|
4
|
-
export const configVersion = 2;
|
|
5
4
|
export const defaultConfig = {
|
|
6
|
-
aliases: {
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
aliases: {
|
|
6
|
+
ui: "@/components/ui",
|
|
7
|
+
styles: "@/styles",
|
|
8
|
+
},
|
|
9
9
|
};
|
|
10
10
|
export async function hasConfig(projectDirectory) {
|
|
11
11
|
try {
|
|
@@ -25,22 +25,24 @@ function ensureRelativePath(projectDirectory, path, name) {
|
|
|
25
25
|
}
|
|
26
26
|
export function validateConfig(config) {
|
|
27
27
|
const candidate = config;
|
|
28
|
-
if (
|
|
29
|
-
throw new Error("
|
|
28
|
+
if (candidate.paths || candidate.tokens) {
|
|
29
|
+
throw new Error("This nooeh.json uses an older format. Run `nooeh init --force` to create alias-based configuration.");
|
|
30
30
|
}
|
|
31
|
-
if (candidate.
|
|
32
|
-
throw new Error(
|
|
31
|
+
if (!candidate.aliases || typeof candidate.aliases !== "object") {
|
|
32
|
+
throw new Error("Configure aliases.");
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const aliases = candidate.aliases;
|
|
35
|
+
if (typeof aliases.ui !== "string" || !aliases.ui.trim()) {
|
|
36
|
+
throw new Error("Configure aliases.ui.");
|
|
36
37
|
}
|
|
37
|
-
if (
|
|
38
|
-
throw new Error("
|
|
38
|
+
if (typeof aliases.styles !== "string" || !aliases.styles.trim()) {
|
|
39
|
+
throw new Error("Configure aliases.styles.");
|
|
39
40
|
}
|
|
40
41
|
return {
|
|
41
|
-
aliases: {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
aliases: {
|
|
43
|
+
ui: aliases.ui,
|
|
44
|
+
styles: aliases.styles,
|
|
45
|
+
},
|
|
44
46
|
};
|
|
45
47
|
}
|
|
46
48
|
function isNotFoundError(error) {
|
|
@@ -61,54 +63,54 @@ export async function readConfig(projectDirectory) {
|
|
|
61
63
|
}
|
|
62
64
|
export async function writeConfig(projectDirectory, config) {
|
|
63
65
|
const validatedConfig = validateConfig(config);
|
|
64
|
-
ensureRelativePath(projectDirectory, validatedConfig.tokens, "tokens");
|
|
65
66
|
const configPath = resolve(projectDirectory, configFileName);
|
|
66
67
|
await writeFile(configPath, `${JSON.stringify(validatedConfig, null, 2)}\n`, "utf8");
|
|
67
68
|
return configPath;
|
|
68
69
|
}
|
|
69
|
-
export function
|
|
70
|
-
ensureRelativePath(projectDirectory,
|
|
71
|
-
return resolve(projectDirectory,
|
|
70
|
+
export function resolveConfigPath(projectDirectory, path, name) {
|
|
71
|
+
ensureRelativePath(projectDirectory, path, name);
|
|
72
|
+
return resolve(projectDirectory, path);
|
|
72
73
|
}
|
|
73
|
-
function
|
|
74
|
-
for (const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
async function readTsConfig(projectDirectory) {
|
|
75
|
+
for (const fileName of ["tsconfig.json", "jsconfig.json"]) {
|
|
76
|
+
try {
|
|
77
|
+
return JSON.parse(await readFile(resolve(projectDirectory, fileName), "utf8"));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (!isNotFoundError(error)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
function resolvePathAlias(alias, paths) {
|
|
88
|
+
for (const [pattern, targets] of Object.entries(paths)) {
|
|
89
|
+
const wildcardIndex = pattern.indexOf("*");
|
|
90
|
+
if (wildcardIndex === -1) {
|
|
91
|
+
if (pattern === alias)
|
|
92
|
+
return targets[0];
|
|
82
93
|
continue;
|
|
83
94
|
}
|
|
84
|
-
const prefix = pattern.slice(0,
|
|
85
|
-
const suffix = pattern.slice(
|
|
95
|
+
const prefix = pattern.slice(0, wildcardIndex);
|
|
96
|
+
const suffix = pattern.slice(wildcardIndex + 1);
|
|
86
97
|
if (!alias.startsWith(prefix) || !alias.endsWith(suffix))
|
|
87
98
|
continue;
|
|
88
|
-
const
|
|
89
|
-
return
|
|
99
|
+
const wildcard = alias.slice(prefix.length, alias.length - suffix.length);
|
|
100
|
+
return targets[0]?.replace("*", wildcard);
|
|
90
101
|
}
|
|
91
102
|
return undefined;
|
|
92
103
|
}
|
|
93
|
-
export async function
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const resolvedPath = resolve(baseDirectory, aliasTarget);
|
|
104
|
-
ensureRelativePath(projectDirectory, resolvedPath, "UI");
|
|
105
|
-
return resolvedPath;
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
if (isNotFoundError(error))
|
|
109
|
-
continue;
|
|
110
|
-
throw error;
|
|
111
|
-
}
|
|
104
|
+
export async function resolveConfigAlias(projectDirectory, alias, name) {
|
|
105
|
+
if (alias.startsWith("@/")) {
|
|
106
|
+
return resolveConfigPath(projectDirectory, join("src", alias.slice(2)), name);
|
|
107
|
+
}
|
|
108
|
+
const tsConfig = await readTsConfig(projectDirectory);
|
|
109
|
+
const target = tsConfig?.compilerOptions?.paths
|
|
110
|
+
? resolvePathAlias(alias, tsConfig.compilerOptions.paths)
|
|
111
|
+
: undefined;
|
|
112
|
+
if (!target) {
|
|
113
|
+
throw new Error(`Could not resolve ${name} (${alias}). Add it to tsconfig.json or jsconfig.json compilerOptions.paths.`);
|
|
112
114
|
}
|
|
113
|
-
|
|
115
|
+
return resolveConfigPath(projectDirectory, join(tsConfig?.compilerOptions?.baseUrl ?? ".", target), name);
|
|
114
116
|
}
|
package/dist/doctor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { access, readFile } from "node:fs/promises";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { hasConfig, readConfig,
|
|
3
|
+
import { hasConfig, readConfig, resolveConfigAlias } from "./config.js";
|
|
4
4
|
async function readPackageJson(projectDirectory) {
|
|
5
5
|
try {
|
|
6
6
|
return JSON.parse(await readFile(resolve(projectDirectory, "package.json"), "utf8"));
|
|
@@ -55,7 +55,7 @@ async function hasStylexCompiler(projectDirectory) {
|
|
|
55
55
|
"rspack.config.js",
|
|
56
56
|
];
|
|
57
57
|
const sources = await Promise.all(configFileNames.map(async (fileName) => readProjectFile(projectDirectory, fileName)));
|
|
58
|
-
return sources.some((source) => source?.includes("@stylexjs/unplugin") && source.includes("stylex("));
|
|
58
|
+
return sources.some((source) => source?.includes("@stylexjs/unplugin") && source.includes("stylex.vite("));
|
|
59
59
|
}
|
|
60
60
|
function hasDependency(packageJson, dependency) {
|
|
61
61
|
return Boolean(packageJson?.dependencies?.[dependency] ?? packageJson?.devDependencies?.[dependency]);
|
|
@@ -66,46 +66,50 @@ export async function doctor(projectDirectory) {
|
|
|
66
66
|
const entrySources = await readEntrySources(projectDirectory);
|
|
67
67
|
if (!(await hasConfig(projectDirectory))) {
|
|
68
68
|
checks.push({
|
|
69
|
-
detail: "Run `nooeh init` to configure
|
|
69
|
+
detail: "Run `nooeh init` to configure UI and styles aliases.",
|
|
70
70
|
name: "nooeh.json",
|
|
71
71
|
status: "warn",
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
else {
|
|
75
75
|
const config = await readConfig(projectDirectory);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const tokenDirectory = resolveTokensPath(projectDirectory, config.tokens);
|
|
83
|
-
const tokenFiles = [
|
|
84
|
-
"color-palette.stylex.ts",
|
|
85
|
-
"tokens.stylex.ts",
|
|
86
|
-
"themes.stylex.ts",
|
|
87
|
-
"theme.ts",
|
|
88
|
-
];
|
|
89
|
-
const hasTokenFiles = await Promise.all(tokenFiles.map(async (fileName) => {
|
|
90
|
-
try {
|
|
91
|
-
await access(resolve(tokenDirectory, fileName));
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
}));
|
|
98
|
-
checks.push(hasTokenFiles.every(Boolean)
|
|
99
|
-
? {
|
|
100
|
-
detail: `${config.tokens} contains local token sources.`,
|
|
101
|
-
name: "Local tokens",
|
|
76
|
+
try {
|
|
77
|
+
const uiDirectory = await resolveConfigAlias(projectDirectory, config.aliases.ui, "aliases.ui");
|
|
78
|
+
const tokenDirectory = await resolveConfigAlias(projectDirectory, config.aliases.styles, "aliases.styles");
|
|
79
|
+
checks.push({
|
|
80
|
+
detail: `${config.aliases.ui} → ${uiDirectory}`,
|
|
81
|
+
name: "UI path",
|
|
102
82
|
status: "pass",
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
83
|
+
});
|
|
84
|
+
const tokenFiles = ["color-palette.stylex.ts", "semantic.stylex.ts", "themes.stylex.ts"];
|
|
85
|
+
const hasTokenFiles = await Promise.all(tokenFiles.map(async (fileName) => {
|
|
86
|
+
try {
|
|
87
|
+
await access(resolve(tokenDirectory, fileName));
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
checks.push(hasTokenFiles.every(Boolean)
|
|
95
|
+
? {
|
|
96
|
+
detail: `${config.aliases.styles} contains local token sources.`,
|
|
97
|
+
name: "Local tokens",
|
|
98
|
+
status: "pass",
|
|
99
|
+
}
|
|
100
|
+
: {
|
|
101
|
+
detail: `Create local token sources in ${config.aliases.styles} with \`nooeh init --force\`.`,
|
|
102
|
+
name: "Local tokens",
|
|
103
|
+
status: "warn",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
checks.push({
|
|
108
|
+
detail: error instanceof Error ? error.message : "Could not resolve nooeh aliases.",
|
|
109
|
+
name: "Aliases",
|
|
107
110
|
status: "warn",
|
|
108
111
|
});
|
|
112
|
+
}
|
|
109
113
|
}
|
|
110
114
|
checks.push(hasDependency(packageJson, "@stylexjs/stylex")
|
|
111
115
|
? { detail: "@stylexjs/stylex is installed.", name: "StyleX runtime", status: "pass" }
|
|
@@ -125,26 +129,15 @@ export async function doctor(projectDirectory) {
|
|
|
125
129
|
name: "StyleX compiler",
|
|
126
130
|
status: "warn",
|
|
127
131
|
});
|
|
128
|
-
checks.push(entrySources.some((source) =>
|
|
129
|
-
? {
|
|
130
|
-
detail: "An application entry imports nooeh global CSS.",
|
|
131
|
-
name: "Global CSS",
|
|
132
|
-
status: "pass",
|
|
133
|
-
}
|
|
134
|
-
: {
|
|
135
|
-
detail: "Import `src/styles/nooeh.css` from an application entry point.",
|
|
136
|
-
name: "Global CSS",
|
|
137
|
-
status: "warn",
|
|
138
|
-
});
|
|
139
|
-
checks.push(entrySources.some((source) => source.includes("applyNooehTheme()"))
|
|
132
|
+
checks.push(entrySources.some((source) => /import\s+["'][^"']+\.css["']/.test(source))
|
|
140
133
|
? {
|
|
141
|
-
detail: "An application entry
|
|
142
|
-
name: "
|
|
134
|
+
detail: "An application entry imports a CSS entry point for StyleX output.",
|
|
135
|
+
name: "CSS entry point",
|
|
143
136
|
status: "pass",
|
|
144
137
|
}
|
|
145
138
|
: {
|
|
146
|
-
detail: "
|
|
147
|
-
name: "
|
|
139
|
+
detail: "Import an application CSS file from an entry point so StyleX can emit CSS.",
|
|
140
|
+
name: "CSS entry point",
|
|
148
141
|
status: "warn",
|
|
149
142
|
});
|
|
150
143
|
checks.push(hasDependency(packageJson, "@stylexjs/unplugin")
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ export async function run(arguments_ = process.argv.slice(2)) {
|
|
|
31
31
|
console.log(`Nooeh CLI
|
|
32
32
|
|
|
33
33
|
Usage:
|
|
34
|
-
nooeh init
|
|
34
|
+
nooeh init [--ui <path>] [--tokens <path>]
|
|
35
35
|
nooeh init --framework vite
|
|
36
36
|
nooeh add <component> [--skip-dependencies] [--dry-run]
|
|
37
37
|
nooeh doctor
|
package/dist/init.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
3
|
import { createInterface } from "node:readline/promises";
|
|
4
|
-
import { configFileName, defaultConfig, hasConfig,
|
|
4
|
+
import { configFileName, defaultConfig, hasConfig, resolveConfigAlias, writeConfig, } from "./config.js";
|
|
5
5
|
import { installDependencies } from "./dependencies.js";
|
|
6
6
|
import { getTokenFiles } from "@nooeh/registry";
|
|
7
7
|
async function ask(question, defaultValue, readline) {
|
|
8
8
|
const answer = await readline.question(`${question} (${defaultValue}) `);
|
|
9
9
|
return answer.trim() || defaultValue;
|
|
10
10
|
}
|
|
11
|
-
function getSourceDirectory(projectDirectory) {
|
|
12
|
-
return join(projectDirectory, "src");
|
|
13
|
-
}
|
|
14
11
|
async function readViteConfig(projectDirectory) {
|
|
15
12
|
const configFileNames = [
|
|
16
13
|
"vite.config.ts",
|
|
@@ -37,60 +34,39 @@ async function readViteConfig(projectDirectory) {
|
|
|
37
34
|
throw new Error("Could not find a Vite config file.");
|
|
38
35
|
}
|
|
39
36
|
function configureVite(source) {
|
|
40
|
-
const importLine = 'import stylex from "@stylexjs/unplugin
|
|
37
|
+
const importLine = 'import stylex from "@stylexjs/unplugin";';
|
|
41
38
|
const pluginPattern = /plugins:\s*\[([^\]]*)\]/s;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
throw new Error("Could not safely update the Vite plugins array. Add stylex({ useCSSLayers: true }) manually.");
|
|
39
|
+
const configPattern = /defineConfig\(\{\s*/;
|
|
40
|
+
if (!source.includes("stylex.vite(") && !pluginPattern.test(source)) {
|
|
41
|
+
throw new Error("Could not safely update the Vite plugins array. Add stylex.vite({ useCSSLayers: true }) manually.");
|
|
46
42
|
}
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
43
|
+
const withStylex = source.includes("stylex.vite(")
|
|
44
|
+
? source
|
|
45
|
+
: (source.includes(importLine) ? source : `${importLine}\n${source}`).replace(pluginPattern, (_, plugins) => {
|
|
46
|
+
const prefix = plugins.trim()
|
|
47
|
+
? `stylex.vite({ useCSSLayers: true }), ${plugins}`
|
|
48
|
+
: "stylex.vite({ useCSSLayers: true })";
|
|
49
|
+
return `plugins: [${prefix}]`;
|
|
50
|
+
});
|
|
51
|
+
if (withStylex.includes("alias:"))
|
|
52
|
+
return withStylex;
|
|
53
|
+
if (!configPattern.test(withStylex)) {
|
|
54
|
+
throw new Error('Could not safely add the "@" Vite alias. Add resolve.alias["@"] manually.');
|
|
55
|
+
}
|
|
56
|
+
return withStylex.replace(configPattern, 'defineConfig({\n resolve: { alias: { "@": new URL("./src", import.meta.url).pathname } },\n ');
|
|
58
57
|
}
|
|
59
58
|
async function writeViteFiles(projectDirectory, tokenDirectory) {
|
|
60
59
|
const { path: configPath, source: configSource } = await readViteConfig(projectDirectory);
|
|
61
60
|
const configuredVite = configureVite(configSource);
|
|
62
|
-
const { entryPath, stylePath, themePath } = getNooehPaths(projectDirectory, tokenDirectory);
|
|
63
|
-
const entrySource = await readFile(entryPath, "utf8");
|
|
64
|
-
const styleImport = 'import "./styles/nooeh.css";';
|
|
65
|
-
const themeImport = `import { applyNooehTheme } from "${toModuleSpecifier(dirname(entryPath), themePath)}";`;
|
|
66
|
-
const themeApply = "applyNooehTheme();";
|
|
67
|
-
const imports = [styleImport, themeImport].filter((line) => !entrySource.includes(line));
|
|
68
|
-
const nextEntrySource = `${imports.join("\n")}\n${entrySource}`;
|
|
69
61
|
await writeNooehFiles(projectDirectory, tokenDirectory);
|
|
70
|
-
await writeFile(entryPath, nextEntrySource.includes(themeApply)
|
|
71
|
-
? nextEntrySource
|
|
72
|
-
: `${imports.length ? `${imports.join("\n")}\n` : ""}${themeApply}\n${entrySource}`, "utf8");
|
|
73
62
|
await writeFile(configPath, configuredVite, "utf8");
|
|
74
|
-
console.log(`Configured Vite and created ${relative(projectDirectory,
|
|
75
|
-
}
|
|
76
|
-
function getNooehPaths(projectDirectory, tokenDirectory) {
|
|
77
|
-
const sourceDirectory = getSourceDirectory(projectDirectory);
|
|
78
|
-
return {
|
|
79
|
-
entryPath: join(sourceDirectory, "main.tsx"),
|
|
80
|
-
stylePath: join(sourceDirectory, "styles", "nooeh.css"),
|
|
81
|
-
themePath: join(tokenDirectory, "theme.ts"),
|
|
82
|
-
};
|
|
63
|
+
console.log(`Configured Vite and created ${relative(projectDirectory, tokenDirectory)}.`);
|
|
83
64
|
}
|
|
84
65
|
async function writeNooehFiles(projectDirectory, tokenDirectory) {
|
|
85
|
-
const { entryPath, stylePath, themePath } = getNooehPaths(projectDirectory, tokenDirectory);
|
|
86
|
-
await mkdir(dirname(stylePath), { recursive: true });
|
|
87
66
|
await mkdir(tokenDirectory, { recursive: true });
|
|
88
|
-
await writeFileIfMissing(stylePath, '@import "@nooeh/ui/global.css";\n');
|
|
89
67
|
for (const file of await getTokenFiles()) {
|
|
90
68
|
await writeFileIfMissing(join(tokenDirectory, file.name), file.content);
|
|
91
69
|
}
|
|
92
|
-
await writeFileIfMissing(themePath, `import { darkColorTheme, darkShadowTheme, lightColorTheme, lightShadowTheme } from "./themes.stylex";\nimport * as stylex from "@stylexjs/stylex";\n\nexport type NooehColorMode = "light" | "dark";\n\nconst themeClassNames = [\n stylex.props(lightColorTheme, lightShadowTheme).className,\n stylex.props(darkColorTheme, darkShadowTheme).className,\n]\n .filter(Boolean)\n .flatMap((className) => className.split(" "));\n\nexport function applyNooehTheme(mode: NooehColorMode = "light") {\n const colorTheme = mode === "dark" ? darkColorTheme : lightColorTheme;\n const shadowTheme = mode === "dark" ? darkShadowTheme : lightShadowTheme;\n const themeClassName = stylex.props(colorTheme, shadowTheme).className ?? "";\n const root = document.documentElement;\n\n root.dataset.theme = mode;\n root.classList.remove(...themeClassNames);\n root.classList.add(...themeClassName.split(" ").filter(Boolean));\n}\n`);
|
|
93
|
-
return { entryPath, stylePath, themePath };
|
|
94
70
|
}
|
|
95
71
|
async function writeFileIfMissing(path, source) {
|
|
96
72
|
try {
|
|
@@ -112,28 +88,32 @@ export async function init(projectDirectory, options) {
|
|
|
112
88
|
if (options.framework && options.framework !== "vite") {
|
|
113
89
|
throw new Error(`Unsupported framework: ${options.framework}. Use vite or omit --framework.`);
|
|
114
90
|
}
|
|
115
|
-
const uiAlias = options
|
|
91
|
+
const uiAlias = options.ui ??
|
|
116
92
|
(readline
|
|
117
|
-
? await ask("Enter the UI alias.", defaultConfig.aliases.ui, readline)
|
|
93
|
+
? await ask("Enter the UI import alias.", defaultConfig.aliases.ui, readline)
|
|
118
94
|
: defaultConfig.aliases.ui);
|
|
119
|
-
const
|
|
95
|
+
const stylesAlias = options.styles ??
|
|
96
|
+
options.tokens ??
|
|
120
97
|
(readline
|
|
121
|
-
? await ask("Enter the
|
|
122
|
-
: defaultConfig.
|
|
123
|
-
const tokenDirectory =
|
|
98
|
+
? await ask("Enter the styles import alias.", defaultConfig.aliases.styles, readline)
|
|
99
|
+
: defaultConfig.aliases.styles);
|
|
100
|
+
const tokenDirectory = await resolveConfigAlias(projectDirectory, stylesAlias, "aliases.styles");
|
|
101
|
+
await resolveConfigAlias(projectDirectory, uiAlias, "aliases.ui");
|
|
124
102
|
if (!options["skip-dependencies"]) {
|
|
125
103
|
await installDependencies(projectDirectory, ["@stylexjs/stylex"]);
|
|
126
|
-
|
|
104
|
+
if (options.framework === "vite") {
|
|
105
|
+
await installDependencies(projectDirectory, ["@stylexjs/unplugin"], true);
|
|
106
|
+
}
|
|
127
107
|
}
|
|
128
108
|
if (options.framework === "vite") {
|
|
129
109
|
await writeViteFiles(projectDirectory, tokenDirectory);
|
|
130
110
|
}
|
|
131
111
|
else {
|
|
132
|
-
|
|
133
|
-
console.log(`Created ${relative(projectDirectory,
|
|
134
|
-
console.log("
|
|
112
|
+
await writeNooehFiles(projectDirectory, tokenDirectory);
|
|
113
|
+
console.log(`Created ${relative(projectDirectory, tokenDirectory)}.`);
|
|
114
|
+
console.log("Configure the StyleX compiler for your bundler before importing added components.");
|
|
135
115
|
}
|
|
136
|
-
await writeConfig(projectDirectory, { aliases: { ui: uiAlias
|
|
116
|
+
await writeConfig(projectDirectory, { aliases: { ui: uiAlias, styles: stylesAlias } });
|
|
137
117
|
}
|
|
138
118
|
finally {
|
|
139
119
|
readline?.close();
|
package/dist/new-component.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { access, mkdir, writeFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
3
|
-
import { readConfig,
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { readConfig, resolveConfigAlias } from "./config.js";
|
|
4
4
|
function toPascalCase(name) {
|
|
5
5
|
return name
|
|
6
6
|
.split("-")
|
|
@@ -13,17 +13,10 @@ export async function newComponent(projectDirectory, name) {
|
|
|
13
13
|
throw new Error("Enter a component name in kebab-case. For example: status-chip.");
|
|
14
14
|
}
|
|
15
15
|
const config = await readConfig(projectDirectory);
|
|
16
|
-
const uiDirectory = await
|
|
16
|
+
const uiDirectory = await resolveConfigAlias(projectDirectory, config.aliases.ui, "aliases.ui");
|
|
17
17
|
const componentName = toPascalCase(name);
|
|
18
18
|
const componentPath = join(uiDirectory, `${name}.tsx`);
|
|
19
|
-
const
|
|
20
|
-
const relativeTokenPath = relative(dirname(componentPath), tokenPath)
|
|
21
|
-
.replace(/\.ts$/, "")
|
|
22
|
-
.split(sep)
|
|
23
|
-
.join("/");
|
|
24
|
-
const tokenImport = relativeTokenPath.startsWith(".")
|
|
25
|
-
? relativeTokenPath
|
|
26
|
-
: `./${relativeTokenPath}`;
|
|
19
|
+
const tokenImport = `${config.aliases.styles}/semantic.stylex`;
|
|
27
20
|
const files = [componentPath];
|
|
28
21
|
for (const file of files) {
|
|
29
22
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nooeh/cli",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"bin": {
|
|
6
6
|
"nooeh": "./dist/cli.js"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@nooeh/registry": "0.1.
|
|
22
|
+
"@nooeh/registry": "0.1.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^22.20.1",
|