@nooeh/cli 0.1.0 → 0.2.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/dist/add.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
3
3
  import { createInterface } from "node:readline/promises";
4
- import { defaultConfig, hasConfig, readConfig, resolveAliasPath, resolveTokensPath, } from "./config.js";
4
+ import { defaultConfig, hasConfig, readConfig, resolveConfigPath } from "./config.js";
5
5
  import { installDependencies } from "./dependencies.js";
6
6
  import { init } from "./init.js";
7
7
  import { resolveComponent } from "./registry.js";
@@ -70,8 +70,8 @@ export async function add(projectDirectory, componentName, options = {}) {
70
70
  }
71
71
  const config = options["dry-run"] && shouldInitialize ? defaultConfig : await readConfig(projectDirectory);
72
72
  const resolved = await resolveComponent(componentName);
73
- const uiDirectory = await resolveAliasPath(projectDirectory, config.aliases.ui);
74
- const tokenDirectory = resolveTokensPath(projectDirectory, config.tokens);
73
+ const uiDirectory = resolveConfigPath(projectDirectory, config.paths.ui, "paths.ui");
74
+ const tokenDirectory = resolveConfigPath(projectDirectory, config.paths.tokens, "paths.tokens");
75
75
  let isOverwriteConfirmed = false;
76
76
  async function confirmOverwrite() {
77
77
  if (isOverwriteConfirmed)
@@ -101,5 +101,6 @@ export async function add(projectDirectory, componentName, options = {}) {
101
101
  return;
102
102
  }
103
103
  console.log(`Added ${componentName}.`);
104
- console.log(`import { ${primaryExport} } from "${config.aliases.ui}/${componentName}"`);
104
+ console.log(`Export: ${primaryExport}`);
105
+ console.log(`Location: ${relative(projectDirectory, join(uiDirectory, `${componentName}.tsx`))}`);
105
106
  }
@@ -6,7 +6,7 @@ export type CliOptions = Record<string, boolean | string | undefined> & {
6
6
  force?: boolean;
7
7
  "skip-dependencies"?: boolean;
8
8
  tokens?: string;
9
- "ui-alias"?: string;
9
+ ui?: string;
10
10
  };
11
11
  export declare function parseArguments(arguments_: readonly string[]): {
12
12
  command: string;
package/dist/config.d.ts CHANGED
@@ -1,16 +1,13 @@
1
1
  export declare const configFileName = "nooeh.json";
2
- export declare const configVersion = 2;
3
2
  export type NooehConfig = {
4
- aliases: {
3
+ paths: {
5
4
  ui: string;
5
+ tokens: 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 resolveTokensPath(projectDirectory: string, tokens: string): string;
16
- export declare function resolveAliasPath(projectDirectory: string, alias: string): Promise<string>;
13
+ export declare function resolveConfigPath(projectDirectory: string, path: string, name: string): string;
package/dist/config.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { access, readFile, writeFile } from "node:fs/promises";
2
2
  import { isAbsolute, relative, resolve } from "node:path";
3
3
  export const configFileName = "nooeh.json";
4
- export const configVersion = 2;
5
4
  export const defaultConfig = {
6
- aliases: { ui: "@/components/ui" },
7
- tokens: "src/styles/nooeh",
8
- version: configVersion,
5
+ paths: {
6
+ ui: "src/components/ui",
7
+ tokens: "src/design/nooeh",
8
+ },
9
9
  };
10
10
  export async function hasConfig(projectDirectory) {
11
11
  try {
@@ -25,22 +25,23 @@ function ensureRelativePath(projectDirectory, path, name) {
25
25
  }
26
26
  export function validateConfig(config) {
27
27
  const candidate = config;
28
- if (!candidate.aliases || typeof candidate.aliases.ui !== "string" || !candidate.aliases.ui) {
29
- throw new Error("Configure aliases.ui.");
28
+ if (!candidate.paths && (candidate.aliases || candidate.tokens)) {
29
+ throw new Error("This nooeh.json uses an older format. Run `nooeh init --force` to create path-based configuration.");
30
30
  }
31
- if (candidate.version !== undefined && candidate.version !== configVersion) {
32
- throw new Error(`Unsupported nooeh.json version: ${String(candidate.version)}`);
31
+ if (!candidate.paths || typeof candidate.paths.ui !== "string" || !candidate.paths.ui.trim()) {
32
+ throw new Error("Configure paths.ui.");
33
33
  }
34
- if (typeof candidate.tokens !== "string" || !candidate.tokens.trim()) {
35
- throw new Error("Configure tokens.");
34
+ if (typeof candidate.paths.tokens !== "string" || !candidate.paths.tokens.trim()) {
35
+ throw new Error("Configure paths.tokens.");
36
36
  }
37
- if (isAbsolute(candidate.tokens)) {
38
- throw new Error("tokens must be inside the project directory.");
37
+ if (isAbsolute(candidate.paths.ui) || isAbsolute(candidate.paths.tokens)) {
38
+ throw new Error("paths must stay inside the project directory.");
39
39
  }
40
40
  return {
41
- aliases: { ui: candidate.aliases.ui },
42
- tokens: candidate.tokens,
43
- version: configVersion,
41
+ paths: {
42
+ ui: candidate.paths.ui,
43
+ tokens: candidate.paths.tokens,
44
+ },
44
45
  };
45
46
  }
46
47
  function isNotFoundError(error) {
@@ -61,54 +62,13 @@ export async function readConfig(projectDirectory) {
61
62
  }
62
63
  export async function writeConfig(projectDirectory, config) {
63
64
  const validatedConfig = validateConfig(config);
64
- ensureRelativePath(projectDirectory, validatedConfig.tokens, "tokens");
65
+ ensureRelativePath(projectDirectory, validatedConfig.paths.ui, "paths.ui");
66
+ ensureRelativePath(projectDirectory, validatedConfig.paths.tokens, "paths.tokens");
65
67
  const configPath = resolve(projectDirectory, configFileName);
66
68
  await writeFile(configPath, `${JSON.stringify(validatedConfig, null, 2)}\n`, "utf8");
67
69
  return configPath;
68
70
  }
69
- export function resolveTokensPath(projectDirectory, tokens) {
70
- ensureRelativePath(projectDirectory, tokens, "tokens");
71
- return resolve(projectDirectory, tokens);
72
- }
73
- function findAliasTarget(alias, paths) {
74
- for (const [pattern, targets] of Object.entries(paths ?? {})) {
75
- const target = targets[0];
76
- if (!target)
77
- continue;
78
- const starIndex = pattern.indexOf("*");
79
- if (starIndex === -1) {
80
- if (alias === pattern)
81
- return target;
82
- continue;
83
- }
84
- const prefix = pattern.slice(0, starIndex);
85
- const suffix = pattern.slice(starIndex + 1);
86
- if (!alias.startsWith(prefix) || !alias.endsWith(suffix))
87
- continue;
88
- const value = alias.slice(prefix.length, alias.length - suffix.length);
89
- return target.replaceAll("*", value);
90
- }
91
- return undefined;
92
- }
93
- export async function resolveAliasPath(projectDirectory, alias) {
94
- for (const fileName of ["tsconfig.json", "jsconfig.json"]) {
95
- const configPath = resolve(projectDirectory, fileName);
96
- try {
97
- const projectConfig = JSON.parse(await readFile(configPath, "utf8"));
98
- const compilerOptions = projectConfig.compilerOptions ?? {};
99
- const aliasTarget = findAliasTarget(alias, compilerOptions.paths);
100
- if (!aliasTarget)
101
- continue;
102
- const baseDirectory = resolve(projectDirectory, compilerOptions.baseUrl ?? ".");
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
- }
112
- }
113
- throw new Error(`Could not find the ${alias} alias in compilerOptions.paths of tsconfig.json or jsconfig.json.`);
71
+ export function resolveConfigPath(projectDirectory, path, name) {
72
+ ensureRelativePath(projectDirectory, path, name);
73
+ return resolve(projectDirectory, path);
114
74
  }
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, resolveAliasPath, resolveTokensPath } from "./config.js";
3
+ import { hasConfig, readConfig, resolveConfigPath } from "./config.js";
4
4
  async function readPackageJson(projectDirectory) {
5
5
  try {
6
6
  return JSON.parse(await readFile(resolve(projectDirectory, "package.json"), "utf8"));
@@ -73,13 +73,13 @@ export async function doctor(projectDirectory) {
73
73
  }
74
74
  else {
75
75
  const config = await readConfig(projectDirectory);
76
- const uiDirectory = await resolveAliasPath(projectDirectory, config.aliases.ui);
76
+ const uiDirectory = resolveConfigPath(projectDirectory, config.paths.ui, "paths.ui");
77
77
  checks.push({
78
- detail: `${config.aliases.ui} → ${uiDirectory}`,
79
- name: "UI alias",
78
+ detail: `${config.paths.ui} → ${uiDirectory}`,
79
+ name: "UI path",
80
80
  status: "pass",
81
81
  });
82
- const tokenDirectory = resolveTokensPath(projectDirectory, config.tokens);
82
+ const tokenDirectory = resolveConfigPath(projectDirectory, config.paths.tokens, "paths.tokens");
83
83
  const tokenFiles = [
84
84
  "color-palette.stylex.ts",
85
85
  "tokens.stylex.ts",
@@ -97,12 +97,12 @@ export async function doctor(projectDirectory) {
97
97
  }));
98
98
  checks.push(hasTokenFiles.every(Boolean)
99
99
  ? {
100
- detail: `${config.tokens} contains local token sources.`,
100
+ detail: `${config.paths.tokens} contains local token sources.`,
101
101
  name: "Local tokens",
102
102
  status: "pass",
103
103
  }
104
104
  : {
105
- detail: `Create local token sources in ${config.tokens} with \`nooeh init --force\`.`,
105
+ detail: `Create local token sources in ${config.paths.tokens} with \`nooeh init --force\`.`,
106
106
  name: "Local tokens",
107
107
  status: "warn",
108
108
  });
@@ -125,14 +125,14 @@ export async function doctor(projectDirectory) {
125
125
  name: "StyleX compiler",
126
126
  status: "warn",
127
127
  });
128
- checks.push(entrySources.some((source) => source.includes("./styles/nooeh.css") || source.includes("@nooeh/ui/global.css"))
128
+ checks.push(entrySources.some((source) => source.includes("nooeh.css") || source.includes("@nooeh/ui/global.css"))
129
129
  ? {
130
130
  detail: "An application entry imports nooeh global CSS.",
131
131
  name: "Global CSS",
132
132
  status: "pass",
133
133
  }
134
134
  : {
135
- detail: "Import `src/styles/nooeh.css` from an application entry point.",
135
+ detail: "Import the generated nooeh.css file from an application entry point.",
136
136
  name: "Global CSS",
137
137
  status: "warn",
138
138
  });
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,7 +1,7 @@
1
1
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { dirname, join, relative, sep } from "node:path";
3
3
  import { createInterface } from "node:readline/promises";
4
- import { configFileName, defaultConfig, hasConfig, resolveTokensPath, writeConfig, } from "./config.js";
4
+ import { configFileName, defaultConfig, hasConfig, resolveConfigPath, 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) {
@@ -61,7 +61,7 @@ async function writeViteFiles(projectDirectory, tokenDirectory) {
61
61
  const configuredVite = configureVite(configSource);
62
62
  const { entryPath, stylePath, themePath } = getNooehPaths(projectDirectory, tokenDirectory);
63
63
  const entrySource = await readFile(entryPath, "utf8");
64
- const styleImport = 'import "./styles/nooeh.css";';
64
+ const styleImport = `import "${toModuleSpecifier(dirname(entryPath), stylePath)}";`;
65
65
  const themeImport = `import { applyNooehTheme } from "${toModuleSpecifier(dirname(entryPath), themePath)}";`;
66
66
  const themeApply = "applyNooehTheme();";
67
67
  const imports = [styleImport, themeImport].filter((line) => !entrySource.includes(line));
@@ -77,7 +77,7 @@ function getNooehPaths(projectDirectory, tokenDirectory) {
77
77
  const sourceDirectory = getSourceDirectory(projectDirectory);
78
78
  return {
79
79
  entryPath: join(sourceDirectory, "main.tsx"),
80
- stylePath: join(sourceDirectory, "styles", "nooeh.css"),
80
+ stylePath: join(dirname(tokenDirectory), "nooeh.css"),
81
81
  themePath: join(tokenDirectory, "theme.ts"),
82
82
  };
83
83
  }
@@ -112,15 +112,16 @@ export async function init(projectDirectory, options) {
112
112
  if (options.framework && options.framework !== "vite") {
113
113
  throw new Error(`Unsupported framework: ${options.framework}. Use vite or omit --framework.`);
114
114
  }
115
- const uiAlias = options["ui-alias"] ??
115
+ const uiPath = options.ui ??
116
116
  (readline
117
- ? await ask("Enter the UI alias.", defaultConfig.aliases.ui, readline)
118
- : defaultConfig.aliases.ui);
117
+ ? await ask("Enter the UI directory.", defaultConfig.paths.ui, readline)
118
+ : defaultConfig.paths.ui);
119
119
  const tokens = options.tokens ??
120
120
  (readline
121
- ? await ask("Enter the token directory.", defaultConfig.tokens, readline)
122
- : defaultConfig.tokens);
123
- const tokenDirectory = resolveTokensPath(projectDirectory, tokens);
121
+ ? await ask("Enter the token directory.", defaultConfig.paths.tokens, readline)
122
+ : defaultConfig.paths.tokens);
123
+ const tokenDirectory = resolveConfigPath(projectDirectory, tokens, "paths.tokens");
124
+ resolveConfigPath(projectDirectory, uiPath, "paths.ui");
124
125
  if (!options["skip-dependencies"]) {
125
126
  await installDependencies(projectDirectory, ["@stylexjs/stylex"]);
126
127
  await installDependencies(projectDirectory, ["@stylexjs/unplugin"], true);
@@ -133,7 +134,7 @@ export async function init(projectDirectory, options) {
133
134
  console.log(`Created ${relative(projectDirectory, stylePath)} and ${relative(projectDirectory, themePath)}.`);
134
135
  console.log("Import the CSS and call applyNooehTheme() from your application entry point.");
135
136
  }
136
- await writeConfig(projectDirectory, { aliases: { ui: uiAlias }, tokens });
137
+ await writeConfig(projectDirectory, { paths: { ui: uiPath, tokens } });
137
138
  }
138
139
  finally {
139
140
  readline?.close();
@@ -1,6 +1,6 @@
1
1
  import { access, mkdir, writeFile } from "node:fs/promises";
2
2
  import { dirname, join, relative, sep } from "node:path";
3
- import { readConfig, resolveAliasPath, resolveTokensPath } from "./config.js";
3
+ import { readConfig, resolveConfigPath } from "./config.js";
4
4
  function toPascalCase(name) {
5
5
  return name
6
6
  .split("-")
@@ -13,10 +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 resolveAliasPath(projectDirectory, config.aliases.ui);
16
+ const uiDirectory = resolveConfigPath(projectDirectory, config.paths.ui, "paths.ui");
17
17
  const componentName = toPascalCase(name);
18
18
  const componentPath = join(uiDirectory, `${name}.tsx`);
19
- const tokenPath = join(resolveTokensPath(projectDirectory, config.tokens), "tokens.stylex.ts");
19
+ const tokenPath = join(resolveConfigPath(projectDirectory, config.paths.tokens, "paths.tokens"), "tokens.stylex.ts");
20
20
  const relativeTokenPath = relative(dirname(componentPath), tokenPath)
21
21
  .replace(/\.ts$/, "")
22
22
  .split(sep)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nooeh/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "nooeh": "./dist/cli.js"