uilint 0.2.14 → 0.2.15
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/index.js +1 -1
- package/dist/{install-ui-H2KOQ6SP.js → install-ui-73AINMZ5.js} +462 -21
- package/dist/install-ui-73AINMZ5.js.map +1 -0
- package/dist/{plan-G43256ML.js → plan-VPDTICSY.js} +4 -4
- package/dist/plan-VPDTICSY.js.map +1 -0
- package/package.json +3 -3
- package/dist/install-ui-H2KOQ6SP.js.map +0 -1
- package/dist/plan-G43256ML.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2805,7 +2805,7 @@ program.command("update").description("Update existing style guide with new styl
|
|
|
2805
2805
|
});
|
|
2806
2806
|
});
|
|
2807
2807
|
program.command("install").description("Install UILint integration").option("--force", "Overwrite existing configuration files").action(async (options) => {
|
|
2808
|
-
const { installUI } = await import("./install-ui-
|
|
2808
|
+
const { installUI } = await import("./install-ui-73AINMZ5.js");
|
|
2809
2809
|
await installUI({ force: options.force });
|
|
2810
2810
|
});
|
|
2811
2811
|
program.command("serve").description("Start WebSocket server for real-time UI linting").option("-p, --port <number>", "Port to listen on", "9234").action(async (options) => {
|
|
@@ -1698,11 +1698,11 @@ import {
|
|
|
1698
1698
|
unlinkSync,
|
|
1699
1699
|
chmodSync
|
|
1700
1700
|
} from "fs";
|
|
1701
|
-
import { dirname as
|
|
1701
|
+
import { dirname as dirname4 } from "path";
|
|
1702
1702
|
|
|
1703
1703
|
// src/utils/react-inject.ts
|
|
1704
1704
|
import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
1705
|
-
import { join as join5 } from "path";
|
|
1705
|
+
import { join as join5, relative as relative3 } from "path";
|
|
1706
1706
|
import { parseModule as parseModule2, generateCode as generateCode2 } from "magicast";
|
|
1707
1707
|
function getDefaultCandidates(projectPath, appRoot) {
|
|
1708
1708
|
const viteMainCandidates = [
|
|
@@ -1759,6 +1759,32 @@ function walkAst(node, visit) {
|
|
|
1759
1759
|
}
|
|
1760
1760
|
}
|
|
1761
1761
|
}
|
|
1762
|
+
function ensureNamedImport(program, from, name) {
|
|
1763
|
+
if (!program || program.type !== "Program") return { changed: false };
|
|
1764
|
+
const existing = findImportDeclaration(program, from);
|
|
1765
|
+
if (existing) {
|
|
1766
|
+
const has = (existing.specifiers ?? []).some(
|
|
1767
|
+
(s) => s?.type === "ImportSpecifier" && (s.imported?.name === name || s.imported?.value === name)
|
|
1768
|
+
);
|
|
1769
|
+
if (has) return { changed: false };
|
|
1770
|
+
const spec = parseModule2(`import { ${name} } from "${from}";`).$ast.body?.[0]?.specifiers?.[0];
|
|
1771
|
+
if (!spec) return { changed: false };
|
|
1772
|
+
existing.specifiers = [...existing.specifiers ?? [], spec];
|
|
1773
|
+
return { changed: true };
|
|
1774
|
+
}
|
|
1775
|
+
const importDecl = parseModule2(`import { ${name} } from "${from}";`).$ast.body?.[0];
|
|
1776
|
+
if (!importDecl) return { changed: false };
|
|
1777
|
+
const body = program.body ?? [];
|
|
1778
|
+
let insertAt = 0;
|
|
1779
|
+
while (insertAt < body.length && isUseClientDirective(body[insertAt])) {
|
|
1780
|
+
insertAt++;
|
|
1781
|
+
}
|
|
1782
|
+
while (insertAt < body.length && body[insertAt]?.type === "ImportDeclaration") {
|
|
1783
|
+
insertAt++;
|
|
1784
|
+
}
|
|
1785
|
+
program.body.splice(insertAt, 0, importDecl);
|
|
1786
|
+
return { changed: true };
|
|
1787
|
+
}
|
|
1762
1788
|
function hasUILintDevtoolsJsx(program) {
|
|
1763
1789
|
let found = false;
|
|
1764
1790
|
walkAst(program, (node) => {
|
|
@@ -1852,7 +1878,204 @@ function ensureSideEffectImport(program, from) {
|
|
|
1852
1878
|
program.body.splice(insertAt, 0, importDecl);
|
|
1853
1879
|
return { changed: true };
|
|
1854
1880
|
}
|
|
1881
|
+
function addDevtoolsToClientComponent(program) {
|
|
1882
|
+
if (!program || program.type !== "Program") return { changed: false };
|
|
1883
|
+
if (hasUILintDevtoolsJsx(program)) return { changed: false };
|
|
1884
|
+
const devtoolsMod = parseModule2(
|
|
1885
|
+
"const __uilint_devtools = (<uilint-devtools />);"
|
|
1886
|
+
);
|
|
1887
|
+
const devtoolsJsx = devtoolsMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
|
|
1888
|
+
if (!devtoolsJsx || devtoolsJsx.type !== "JSXElement")
|
|
1889
|
+
return { changed: false };
|
|
1890
|
+
let added = false;
|
|
1891
|
+
walkAst(program, (node) => {
|
|
1892
|
+
if (added) return;
|
|
1893
|
+
if (node.type !== "JSXElement" && node.type !== "JSXFragment") return;
|
|
1894
|
+
const children = node.children ?? [];
|
|
1895
|
+
const childrenIndex = children.findIndex(
|
|
1896
|
+
(child) => child?.type === "JSXExpressionContainer" && child.expression?.type === "Identifier" && child.expression.name === "children"
|
|
1897
|
+
);
|
|
1898
|
+
if (childrenIndex !== -1) {
|
|
1899
|
+
children.splice(childrenIndex + 1, 0, devtoolsJsx);
|
|
1900
|
+
added = true;
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
if (added) return { changed: true };
|
|
1904
|
+
walkAst(program, (node) => {
|
|
1905
|
+
if (added) return;
|
|
1906
|
+
if (node.type !== "ReturnStatement") return;
|
|
1907
|
+
const arg = node.argument;
|
|
1908
|
+
if (!arg) return;
|
|
1909
|
+
if (arg.type !== "JSXElement" && arg.type !== "JSXFragment") return;
|
|
1910
|
+
const fragmentMod = parseModule2("const __fragment = (<></>);");
|
|
1911
|
+
const fragmentJsx = fragmentMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
|
|
1912
|
+
if (!fragmentJsx) return;
|
|
1913
|
+
fragmentJsx.children = [arg, devtoolsJsx];
|
|
1914
|
+
node.argument = fragmentJsx;
|
|
1915
|
+
added = true;
|
|
1916
|
+
});
|
|
1917
|
+
if (!added) {
|
|
1918
|
+
throw new Error(
|
|
1919
|
+
"Could not find a suitable location to add devtools. Expected a component with JSX return or {children}."
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
return { changed: true };
|
|
1923
|
+
}
|
|
1924
|
+
function generateProvidersContent(isTypeScript) {
|
|
1925
|
+
const ext = isTypeScript ? "tsx" : "jsx";
|
|
1926
|
+
const typeAnnotation = isTypeScript ? ": { children: React.ReactNode }" : "";
|
|
1927
|
+
return `"use client";
|
|
1928
|
+
|
|
1929
|
+
import React from "react";
|
|
1930
|
+
import "uilint-react/devtools";
|
|
1931
|
+
|
|
1932
|
+
export function Providers({ children }${typeAnnotation}) {
|
|
1933
|
+
return (
|
|
1934
|
+
<>
|
|
1935
|
+
{children}
|
|
1936
|
+
<uilint-devtools />
|
|
1937
|
+
</>
|
|
1938
|
+
);
|
|
1939
|
+
}
|
|
1940
|
+
`;
|
|
1941
|
+
}
|
|
1942
|
+
function wrapChildrenWithProviders(program, providersImportPath) {
|
|
1943
|
+
if (!program || program.type !== "Program") return { changed: false };
|
|
1944
|
+
let hasProvidersImport = false;
|
|
1945
|
+
for (const stmt of program.body ?? []) {
|
|
1946
|
+
if (stmt?.type !== "ImportDeclaration") continue;
|
|
1947
|
+
if (stmt.source?.value === providersImportPath) {
|
|
1948
|
+
hasProvidersImport = true;
|
|
1949
|
+
break;
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
if (!hasProvidersImport) {
|
|
1953
|
+
const importRes = ensureNamedImport(program, providersImportPath, "Providers");
|
|
1954
|
+
if (!importRes.changed) return { changed: false };
|
|
1955
|
+
}
|
|
1956
|
+
let wrapped = false;
|
|
1957
|
+
walkAst(program, (node) => {
|
|
1958
|
+
if (wrapped) return;
|
|
1959
|
+
if (node.type !== "JSXElement" && node.type !== "JSXFragment") return;
|
|
1960
|
+
const children = node.children ?? [];
|
|
1961
|
+
const childrenIndex = children.findIndex(
|
|
1962
|
+
(child) => child?.type === "JSXExpressionContainer" && child.expression?.type === "Identifier" && child.expression.name === "children"
|
|
1963
|
+
);
|
|
1964
|
+
if (childrenIndex === -1) return;
|
|
1965
|
+
const providersMod = parseModule2(
|
|
1966
|
+
"const __providers = (<Providers>{children}</Providers>);"
|
|
1967
|
+
);
|
|
1968
|
+
const providersJsx = providersMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
|
|
1969
|
+
if (!providersJsx) return;
|
|
1970
|
+
children[childrenIndex] = providersJsx;
|
|
1971
|
+
wrapped = true;
|
|
1972
|
+
});
|
|
1973
|
+
if (!wrapped) {
|
|
1974
|
+
throw new Error(
|
|
1975
|
+
"Could not find {children} in layout to wrap with Providers."
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
return { changed: true };
|
|
1979
|
+
}
|
|
1980
|
+
function findLayoutFile(projectPath, appRoot) {
|
|
1981
|
+
const extensions = [".tsx", ".jsx", ".ts", ".js"];
|
|
1982
|
+
for (const ext of extensions) {
|
|
1983
|
+
const layoutPath = join5(projectPath, appRoot, `layout${ext}`);
|
|
1984
|
+
if (existsSync5(layoutPath)) return layoutPath;
|
|
1985
|
+
}
|
|
1986
|
+
return null;
|
|
1987
|
+
}
|
|
1988
|
+
async function createProvidersAndModifyLayout(projectPath, appRoot) {
|
|
1989
|
+
const layoutPath = findLayoutFile(projectPath, appRoot);
|
|
1990
|
+
if (!layoutPath) {
|
|
1991
|
+
throw new Error(`Could not find layout file in ${appRoot}`);
|
|
1992
|
+
}
|
|
1993
|
+
const isTypeScript = layoutPath.endsWith(".tsx") || layoutPath.endsWith(".ts");
|
|
1994
|
+
const providersExt = isTypeScript ? ".tsx" : ".jsx";
|
|
1995
|
+
const providersPath = join5(projectPath, appRoot, `providers${providersExt}`);
|
|
1996
|
+
if (existsSync5(providersPath)) {
|
|
1997
|
+
throw new Error(
|
|
1998
|
+
`providers${providersExt} already exists. Please select it from the list instead.`
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
const providersContent = generateProvidersContent(isTypeScript);
|
|
2002
|
+
writeFileSync2(providersPath, providersContent, "utf-8");
|
|
2003
|
+
const layoutContent = readFileSync5(layoutPath, "utf-8");
|
|
2004
|
+
let layoutMod;
|
|
2005
|
+
try {
|
|
2006
|
+
layoutMod = parseModule2(layoutContent);
|
|
2007
|
+
} catch {
|
|
2008
|
+
throw new Error(
|
|
2009
|
+
`Unable to parse ${relative3(projectPath, layoutPath)} as JavaScript/TypeScript.`
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
2012
|
+
const layoutProgram = layoutMod.$ast;
|
|
2013
|
+
const wrapRes = wrapChildrenWithProviders(layoutProgram, "./providers");
|
|
2014
|
+
if (wrapRes.changed) {
|
|
2015
|
+
const updatedLayout = generateCode2(layoutMod).code;
|
|
2016
|
+
writeFileSync2(layoutPath, updatedLayout, "utf-8");
|
|
2017
|
+
}
|
|
2018
|
+
return {
|
|
2019
|
+
providersFile: relative3(projectPath, providersPath),
|
|
2020
|
+
layoutFile: relative3(projectPath, layoutPath),
|
|
2021
|
+
modified: true
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
1855
2024
|
async function installReactUILintOverlay(opts) {
|
|
2025
|
+
if (opts.createProviders) {
|
|
2026
|
+
const result = await createProvidersAndModifyLayout(
|
|
2027
|
+
opts.projectPath,
|
|
2028
|
+
opts.appRoot
|
|
2029
|
+
);
|
|
2030
|
+
return {
|
|
2031
|
+
targetFile: result.providersFile,
|
|
2032
|
+
modified: result.modified,
|
|
2033
|
+
createdFile: result.providersFile,
|
|
2034
|
+
layoutModified: result.layoutFile
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
if (opts.targetFile) {
|
|
2038
|
+
const absTarget2 = opts.targetFile;
|
|
2039
|
+
const relTarget = relative3(opts.projectPath, absTarget2);
|
|
2040
|
+
if (!existsSync5(absTarget2)) {
|
|
2041
|
+
throw new Error(`Target file not found: ${relTarget}`);
|
|
2042
|
+
}
|
|
2043
|
+
const original2 = readFileSync5(absTarget2, "utf-8");
|
|
2044
|
+
let mod2;
|
|
2045
|
+
try {
|
|
2046
|
+
mod2 = parseModule2(original2);
|
|
2047
|
+
} catch {
|
|
2048
|
+
throw new Error(
|
|
2049
|
+
`Unable to parse ${relTarget} as JavaScript/TypeScript. Please update it manually.`
|
|
2050
|
+
);
|
|
2051
|
+
}
|
|
2052
|
+
const program2 = mod2.$ast;
|
|
2053
|
+
const hasDevtoolsImport2 = !!findImportDeclaration(program2, "uilint-react/devtools");
|
|
2054
|
+
const hasOldImport2 = !!findImportDeclaration(program2, "uilint-react");
|
|
2055
|
+
const alreadyConfigured2 = (hasDevtoolsImport2 || hasOldImport2) && hasUILintDevtoolsJsx(program2);
|
|
2056
|
+
if (alreadyConfigured2) {
|
|
2057
|
+
return {
|
|
2058
|
+
targetFile: relTarget,
|
|
2059
|
+
modified: false,
|
|
2060
|
+
alreadyConfigured: true
|
|
2061
|
+
};
|
|
2062
|
+
}
|
|
2063
|
+
let changed2 = false;
|
|
2064
|
+
const importRes2 = ensureSideEffectImport(program2, "uilint-react/devtools");
|
|
2065
|
+
if (importRes2.changed) changed2 = true;
|
|
2066
|
+
const addRes2 = addDevtoolsToClientComponent(program2);
|
|
2067
|
+
if (addRes2.changed) changed2 = true;
|
|
2068
|
+
const updated2 = changed2 ? generateCode2(mod2).code : original2;
|
|
2069
|
+
const modified2 = updated2 !== original2;
|
|
2070
|
+
if (modified2) {
|
|
2071
|
+
writeFileSync2(absTarget2, updated2, "utf-8");
|
|
2072
|
+
}
|
|
2073
|
+
return {
|
|
2074
|
+
targetFile: relTarget,
|
|
2075
|
+
modified: modified2,
|
|
2076
|
+
alreadyConfigured: false
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
1856
2079
|
const candidates = getDefaultCandidates(opts.projectPath, opts.appRoot);
|
|
1857
2080
|
if (!candidates.length) {
|
|
1858
2081
|
throw new Error(
|
|
@@ -2742,7 +2965,7 @@ async function installNextUILintRoutes(opts) {
|
|
|
2742
2965
|
// src/utils/prettier.ts
|
|
2743
2966
|
import { existsSync as existsSync9 } from "fs";
|
|
2744
2967
|
import { spawn } from "child_process";
|
|
2745
|
-
import { join as join9, dirname as
|
|
2968
|
+
import { join as join9, dirname as dirname3 } from "path";
|
|
2746
2969
|
function getPrettierPath(projectPath) {
|
|
2747
2970
|
const localPath = join9(projectPath, "node_modules", ".bin", "prettier");
|
|
2748
2971
|
if (existsSync9(localPath)) return localPath;
|
|
@@ -2750,7 +2973,7 @@ function getPrettierPath(projectPath) {
|
|
|
2750
2973
|
for (let i = 0; i < 10; i++) {
|
|
2751
2974
|
const binPath = join9(dir, "node_modules", ".bin", "prettier");
|
|
2752
2975
|
if (existsSync9(binPath)) return binPath;
|
|
2753
|
-
const parent =
|
|
2976
|
+
const parent = dirname3(dir);
|
|
2754
2977
|
if (parent === dir) break;
|
|
2755
2978
|
dir = parent;
|
|
2756
2979
|
}
|
|
@@ -2904,7 +3127,7 @@ async function executeAction(action, options) {
|
|
|
2904
3127
|
wouldDo: `Create file: ${action.path}${action.permissions ? ` (mode: ${action.permissions.toString(8)})` : ""}`
|
|
2905
3128
|
};
|
|
2906
3129
|
}
|
|
2907
|
-
const dir =
|
|
3130
|
+
const dir = dirname4(action.path);
|
|
2908
3131
|
if (!existsSync10(dir)) {
|
|
2909
3132
|
mkdirSync(dir, { recursive: true });
|
|
2910
3133
|
}
|
|
@@ -2930,7 +3153,7 @@ async function executeAction(action, options) {
|
|
|
2930
3153
|
}
|
|
2931
3154
|
}
|
|
2932
3155
|
const merged = deepMerge(existing, action.merge);
|
|
2933
|
-
const dir =
|
|
3156
|
+
const dir = dirname4(action.path);
|
|
2934
3157
|
if (!existsSync10(dir)) {
|
|
2935
3158
|
mkdirSync(dir, { recursive: true });
|
|
2936
3159
|
}
|
|
@@ -3024,11 +3247,12 @@ async function executeInjectEslint(action, options) {
|
|
|
3024
3247
|
}
|
|
3025
3248
|
async function executeInjectReact(action, options) {
|
|
3026
3249
|
const { dryRun = false } = options;
|
|
3250
|
+
const dryRunDescription = action.createProviders ? `Create providers.tsx and inject <uilint-devtools /> in: ${action.projectPath}` : action.targetFile ? `Inject <uilint-devtools /> into: ${action.targetFile}` : `Inject <uilint-devtools /> into React app: ${action.projectPath}`;
|
|
3027
3251
|
if (dryRun) {
|
|
3028
3252
|
return {
|
|
3029
3253
|
action,
|
|
3030
3254
|
success: true,
|
|
3031
|
-
wouldDo:
|
|
3255
|
+
wouldDo: dryRunDescription
|
|
3032
3256
|
};
|
|
3033
3257
|
}
|
|
3034
3258
|
const result = await installReactUILintOverlay({
|
|
@@ -3036,7 +3260,10 @@ async function executeInjectReact(action, options) {
|
|
|
3036
3260
|
appRoot: action.appRoot,
|
|
3037
3261
|
mode: action.mode,
|
|
3038
3262
|
force: false,
|
|
3039
|
-
//
|
|
3263
|
+
// Pass through targetFile and createProviders from the action
|
|
3264
|
+
targetFile: action.targetFile,
|
|
3265
|
+
createProviders: action.createProviders,
|
|
3266
|
+
// Auto-select first choice for execute phase (fallback if no targetFile)
|
|
3040
3267
|
confirmFileChoice: async (choices) => choices[0]
|
|
3041
3268
|
});
|
|
3042
3269
|
const success = result.modified || result.alreadyConfigured === true;
|
|
@@ -3719,6 +3946,143 @@ var eslintInstaller = {
|
|
|
3719
3946
|
}
|
|
3720
3947
|
};
|
|
3721
3948
|
|
|
3949
|
+
// src/utils/client-boundary-tracer.ts
|
|
3950
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
3951
|
+
import { join as join13, dirname as dirname5, relative as relative4 } from "path";
|
|
3952
|
+
import { parseModule as parseModule5 } from "magicast";
|
|
3953
|
+
function hasUseClientDirective(filePath) {
|
|
3954
|
+
try {
|
|
3955
|
+
const content = readFileSync9(filePath, "utf-8");
|
|
3956
|
+
const mod = parseModule5(content);
|
|
3957
|
+
const program = mod.$ast;
|
|
3958
|
+
if (!program || program.type !== "Program") return false;
|
|
3959
|
+
const firstStmt = program.body?.[0];
|
|
3960
|
+
return firstStmt?.type === "ExpressionStatement" && firstStmt.expression?.type === "StringLiteral" && (firstStmt.expression.value === "use client" || firstStmt.expression.value === "use client");
|
|
3961
|
+
} catch {
|
|
3962
|
+
return false;
|
|
3963
|
+
}
|
|
3964
|
+
}
|
|
3965
|
+
function extractImports(program) {
|
|
3966
|
+
const imports = [];
|
|
3967
|
+
if (!program || program.type !== "Program") return imports;
|
|
3968
|
+
for (const stmt of program.body ?? []) {
|
|
3969
|
+
if (stmt?.type !== "ImportDeclaration") continue;
|
|
3970
|
+
const source = stmt.source?.value;
|
|
3971
|
+
if (typeof source !== "string") continue;
|
|
3972
|
+
if (!source.startsWith(".") && !source.startsWith("@/") && !source.startsWith("~/")) {
|
|
3973
|
+
continue;
|
|
3974
|
+
}
|
|
3975
|
+
const specifiers = [];
|
|
3976
|
+
for (const spec of stmt.specifiers ?? []) {
|
|
3977
|
+
if (spec.type === "ImportDefaultSpecifier") {
|
|
3978
|
+
specifiers.push("default");
|
|
3979
|
+
} else if (spec.type === "ImportSpecifier") {
|
|
3980
|
+
const name = spec.imported?.name ?? spec.imported?.value;
|
|
3981
|
+
if (name) specifiers.push(name);
|
|
3982
|
+
} else if (spec.type === "ImportNamespaceSpecifier") {
|
|
3983
|
+
specifiers.push("*");
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
imports.push({ source, specifiers });
|
|
3987
|
+
}
|
|
3988
|
+
return imports;
|
|
3989
|
+
}
|
|
3990
|
+
function resolveImportPath(importSource, fromFile, projectPath) {
|
|
3991
|
+
const fromDir = dirname5(fromFile);
|
|
3992
|
+
let basePath;
|
|
3993
|
+
if (importSource.startsWith("@/")) {
|
|
3994
|
+
const withoutAlias = importSource.slice(2);
|
|
3995
|
+
const srcPath = join13(projectPath, "src", withoutAlias);
|
|
3996
|
+
const rootPath = join13(projectPath, withoutAlias);
|
|
3997
|
+
basePath = existsSync12(dirname5(srcPath)) ? srcPath : rootPath;
|
|
3998
|
+
} else if (importSource.startsWith("~/")) {
|
|
3999
|
+
basePath = join13(projectPath, importSource.slice(2));
|
|
4000
|
+
} else if (importSource.startsWith(".")) {
|
|
4001
|
+
basePath = join13(fromDir, importSource);
|
|
4002
|
+
} else {
|
|
4003
|
+
return null;
|
|
4004
|
+
}
|
|
4005
|
+
const extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
4006
|
+
for (const ext of extensions) {
|
|
4007
|
+
const fullPath = basePath + ext;
|
|
4008
|
+
if (existsSync12(fullPath)) return fullPath;
|
|
4009
|
+
}
|
|
4010
|
+
for (const ext of extensions) {
|
|
4011
|
+
const indexPath = join13(basePath, `index${ext}`);
|
|
4012
|
+
if (existsSync12(indexPath)) return indexPath;
|
|
4013
|
+
}
|
|
4014
|
+
if (existsSync12(basePath)) return basePath;
|
|
4015
|
+
return null;
|
|
4016
|
+
}
|
|
4017
|
+
function findLayoutFile2(projectPath, appRoot) {
|
|
4018
|
+
const extensions = [".tsx", ".jsx", ".ts", ".js"];
|
|
4019
|
+
for (const ext of extensions) {
|
|
4020
|
+
const layoutPath = join13(projectPath, appRoot, `layout${ext}`);
|
|
4021
|
+
if (existsSync12(layoutPath)) return layoutPath;
|
|
4022
|
+
}
|
|
4023
|
+
return null;
|
|
4024
|
+
}
|
|
4025
|
+
function traceClientBoundaries(projectPath, appRoot) {
|
|
4026
|
+
const layoutFile = findLayoutFile2(projectPath, appRoot);
|
|
4027
|
+
if (!layoutFile) {
|
|
4028
|
+
return null;
|
|
4029
|
+
}
|
|
4030
|
+
const layoutIsClient = hasUseClientDirective(layoutFile);
|
|
4031
|
+
const layoutRelative = relative4(projectPath, layoutFile);
|
|
4032
|
+
if (layoutIsClient) {
|
|
4033
|
+
return {
|
|
4034
|
+
layoutIsClient: true,
|
|
4035
|
+
clientBoundaries: [],
|
|
4036
|
+
layoutFile,
|
|
4037
|
+
layoutRelative
|
|
4038
|
+
};
|
|
4039
|
+
}
|
|
4040
|
+
let program;
|
|
4041
|
+
try {
|
|
4042
|
+
const content = readFileSync9(layoutFile, "utf-8");
|
|
4043
|
+
const mod = parseModule5(content);
|
|
4044
|
+
program = mod.$ast;
|
|
4045
|
+
} catch {
|
|
4046
|
+
return {
|
|
4047
|
+
layoutIsClient: false,
|
|
4048
|
+
clientBoundaries: [],
|
|
4049
|
+
layoutFile,
|
|
4050
|
+
layoutRelative
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
const imports = extractImports(program);
|
|
4054
|
+
const clientBoundaries = [];
|
|
4055
|
+
for (const imp of imports) {
|
|
4056
|
+
const resolvedPath = resolveImportPath(imp.source, layoutFile, projectPath);
|
|
4057
|
+
if (!resolvedPath) continue;
|
|
4058
|
+
if (hasUseClientDirective(resolvedPath)) {
|
|
4059
|
+
clientBoundaries.push({
|
|
4060
|
+
filePath: resolvedPath,
|
|
4061
|
+
relativePath: relative4(projectPath, resolvedPath),
|
|
4062
|
+
componentNames: imp.specifiers,
|
|
4063
|
+
importSource: imp.source
|
|
4064
|
+
});
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
4067
|
+
return {
|
|
4068
|
+
layoutIsClient: false,
|
|
4069
|
+
clientBoundaries,
|
|
4070
|
+
layoutFile,
|
|
4071
|
+
layoutRelative
|
|
4072
|
+
};
|
|
4073
|
+
}
|
|
4074
|
+
function providersFileExists(projectPath, appRoot) {
|
|
4075
|
+
const extensions = [".tsx", ".jsx", ".ts", ".js"];
|
|
4076
|
+
const names = ["providers", "Providers"];
|
|
4077
|
+
for (const name of names) {
|
|
4078
|
+
for (const ext of extensions) {
|
|
4079
|
+
const providersPath = join13(projectPath, appRoot, `${name}${ext}`);
|
|
4080
|
+
if (existsSync12(providersPath)) return providersPath;
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
return null;
|
|
4084
|
+
}
|
|
4085
|
+
|
|
3722
4086
|
// src/commands/install/installers/next-overlay.ts
|
|
3723
4087
|
var nextOverlayInstaller = {
|
|
3724
4088
|
id: "next",
|
|
@@ -3729,21 +4093,95 @@ var nextOverlayInstaller = {
|
|
|
3729
4093
|
return project.nextApps.length > 0;
|
|
3730
4094
|
},
|
|
3731
4095
|
getTargets(project) {
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
4096
|
+
const targets = [];
|
|
4097
|
+
for (const app of project.nextApps) {
|
|
4098
|
+
const traceResult = traceClientBoundaries(
|
|
4099
|
+
app.projectPath,
|
|
4100
|
+
app.detection.appRoot
|
|
4101
|
+
);
|
|
4102
|
+
if (!traceResult) {
|
|
4103
|
+
targets.push({
|
|
4104
|
+
id: `next-${app.projectPath}`,
|
|
4105
|
+
label: app.projectPath.split("/").pop() || app.projectPath,
|
|
4106
|
+
path: app.projectPath,
|
|
4107
|
+
hint: "App Router (no layout found)",
|
|
4108
|
+
isInstalled: false
|
|
4109
|
+
});
|
|
4110
|
+
continue;
|
|
4111
|
+
}
|
|
4112
|
+
if (traceResult.layoutIsClient) {
|
|
4113
|
+
targets.push({
|
|
4114
|
+
id: `next-${app.projectPath}`,
|
|
4115
|
+
label: app.projectPath.split("/").pop() || app.projectPath,
|
|
4116
|
+
path: app.projectPath,
|
|
4117
|
+
hint: "App Router",
|
|
4118
|
+
isInstalled: false,
|
|
4119
|
+
targetFile: traceResult.layoutFile
|
|
4120
|
+
});
|
|
4121
|
+
continue;
|
|
4122
|
+
}
|
|
4123
|
+
const existingProviders = providersFileExists(
|
|
4124
|
+
app.projectPath,
|
|
4125
|
+
app.detection.appRoot
|
|
4126
|
+
);
|
|
4127
|
+
if (!existingProviders) {
|
|
4128
|
+
targets.push({
|
|
4129
|
+
id: `next-${app.projectPath}-create-providers`,
|
|
4130
|
+
label: `${app.projectPath.split("/").pop() || app.projectPath}`,
|
|
4131
|
+
path: app.projectPath,
|
|
4132
|
+
hint: "Create providers.tsx (Recommended)",
|
|
4133
|
+
isInstalled: false,
|
|
4134
|
+
createProviders: true
|
|
4135
|
+
});
|
|
4136
|
+
}
|
|
4137
|
+
for (const boundary of traceResult.clientBoundaries) {
|
|
4138
|
+
const componentNames = boundary.componentNames.length > 0 ? boundary.componentNames.join(", ") : "default";
|
|
4139
|
+
targets.push({
|
|
4140
|
+
id: `next-${app.projectPath}-${boundary.relativePath}`,
|
|
4141
|
+
label: `${app.projectPath.split("/").pop() || app.projectPath}`,
|
|
4142
|
+
path: app.projectPath,
|
|
4143
|
+
hint: `${boundary.relativePath} (${componentNames})`,
|
|
4144
|
+
isInstalled: false,
|
|
4145
|
+
targetFile: boundary.filePath
|
|
4146
|
+
});
|
|
4147
|
+
}
|
|
4148
|
+
if (existingProviders) {
|
|
4149
|
+
const relativePath = existingProviders.replace(app.projectPath + "/", "").replace(app.projectPath, "");
|
|
4150
|
+
const alreadyListed = traceResult.clientBoundaries.some(
|
|
4151
|
+
(b) => b.filePath === existingProviders
|
|
4152
|
+
);
|
|
4153
|
+
if (!alreadyListed) {
|
|
4154
|
+
targets.push({
|
|
4155
|
+
id: `next-${app.projectPath}-existing-providers`,
|
|
4156
|
+
label: `${app.projectPath.split("/").pop() || app.projectPath}`,
|
|
4157
|
+
path: app.projectPath,
|
|
4158
|
+
hint: `${relativePath} (existing)`,
|
|
4159
|
+
isInstalled: false,
|
|
4160
|
+
targetFile: existingProviders
|
|
4161
|
+
});
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
if (targets.filter((t) => t.path === app.projectPath).length === 0) {
|
|
4165
|
+
targets.push({
|
|
4166
|
+
id: `next-${app.projectPath}-create-providers`,
|
|
4167
|
+
label: `${app.projectPath.split("/").pop() || app.projectPath}`,
|
|
4168
|
+
path: app.projectPath,
|
|
4169
|
+
hint: "Create providers.tsx",
|
|
4170
|
+
isInstalled: false,
|
|
4171
|
+
createProviders: true
|
|
4172
|
+
});
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
4175
|
+
return targets;
|
|
3740
4176
|
},
|
|
3741
4177
|
plan(targets, config, project) {
|
|
3742
4178
|
const actions = [];
|
|
3743
4179
|
const dependencies = [];
|
|
3744
4180
|
if (targets.length === 0) return { actions, dependencies };
|
|
3745
4181
|
const target = targets[0];
|
|
3746
|
-
const appInfo = project.nextApps.find(
|
|
4182
|
+
const appInfo = project.nextApps.find(
|
|
4183
|
+
(app) => app.projectPath === target.path
|
|
4184
|
+
);
|
|
3747
4185
|
if (!appInfo) return { actions, dependencies };
|
|
3748
4186
|
const { projectPath, detection } = appInfo;
|
|
3749
4187
|
actions.push({
|
|
@@ -3760,7 +4198,9 @@ var nextOverlayInstaller = {
|
|
|
3760
4198
|
type: "inject_react",
|
|
3761
4199
|
projectPath,
|
|
3762
4200
|
appRoot: detection.appRoot,
|
|
3763
|
-
mode: "next"
|
|
4201
|
+
mode: "next",
|
|
4202
|
+
targetFile: target.targetFile,
|
|
4203
|
+
createProviders: target.createProviders
|
|
3764
4204
|
});
|
|
3765
4205
|
actions.push({
|
|
3766
4206
|
type: "inject_next_config",
|
|
@@ -3785,10 +4225,11 @@ var nextOverlayInstaller = {
|
|
|
3785
4225
|
message: "Installing dependencies",
|
|
3786
4226
|
detail: "\u2192 uilint-react, uilint-core, jsx-loc-plugin"
|
|
3787
4227
|
};
|
|
4228
|
+
const injectDetail = target.createProviders ? "\u2192 Creating providers.tsx" : target.targetFile ? `\u2192 ${target.hint || "client component"}` : "\u2192 <uilint-devtools /> in root layout";
|
|
3788
4229
|
yield {
|
|
3789
4230
|
type: "progress",
|
|
3790
4231
|
message: "Injecting devtools component",
|
|
3791
|
-
detail:
|
|
4232
|
+
detail: injectDetail
|
|
3792
4233
|
};
|
|
3793
4234
|
yield {
|
|
3794
4235
|
type: "progress",
|
|
@@ -3962,7 +4403,7 @@ async function installUI(options = {}, executeOptions = {}) {
|
|
|
3962
4403
|
console.log("\nNo items selected for installation");
|
|
3963
4404
|
process.exit(0);
|
|
3964
4405
|
}
|
|
3965
|
-
const { createPlan } = await import("./plan-
|
|
4406
|
+
const { createPlan } = await import("./plan-VPDTICSY.js");
|
|
3966
4407
|
const plan = createPlan(project, choices, { force: options.force });
|
|
3967
4408
|
const result = await execute(plan, {
|
|
3968
4409
|
...executeOptions,
|
|
@@ -3987,4 +4428,4 @@ async function installUI(options = {}, executeOptions = {}) {
|
|
|
3987
4428
|
export {
|
|
3988
4429
|
installUI
|
|
3989
4430
|
};
|
|
3990
|
-
//# sourceMappingURL=install-ui-
|
|
4431
|
+
//# sourceMappingURL=install-ui-73AINMZ5.js.map
|