@clarify-labs/cli 0.8.2 → 0.9.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/output/cli.cjs +2 -2
- package/output/cli.cjs.map +1 -1
- package/output/cli.js +2 -2
- package/output/cli.js.map +1 -1
- package/output/core/dev-routes.d.ts +58 -0
- package/output/core/project-info.d.ts +42 -0
- package/output/core/user-config.d.ts +6 -0
- package/output/index.cjs +1 -1
- package/output/index.js +1 -1
- package/output/{plugin-DyceHdXd.cjs → plugin-JvxU6ZjU.cjs} +204 -37
- package/output/plugin-JvxU6ZjU.cjs.map +1 -0
- package/output/{plugin-D5EF3pYl.js → plugin-_mqQSBqE.js} +205 -38
- package/output/plugin-_mqQSBqE.js.map +1 -0
- package/package.json +3 -3
- package/output/plugin-D5EF3pYl.js.map +0 -1
- package/output/plugin-DyceHdXd.cjs.map +0 -1
|
@@ -1772,6 +1772,126 @@ function resolveProjectConfig(config = {}) {
|
|
|
1772
1772
|
tabs: config.tabs
|
|
1773
1773
|
};
|
|
1774
1774
|
}
|
|
1775
|
+
/** Serialize a ContentRoute into the minimal shape exposed to tooling. */
|
|
1776
|
+
function toDevRouteEntry(route) {
|
|
1777
|
+
return {
|
|
1778
|
+
path: route.path,
|
|
1779
|
+
filePath: route.filePath,
|
|
1780
|
+
locale: route.locale,
|
|
1781
|
+
basePath: route.basePath,
|
|
1782
|
+
kind: route.kind,
|
|
1783
|
+
title: route.title
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Resolve a single file path to its preview route.
|
|
1788
|
+
*
|
|
1789
|
+
* Selection order:
|
|
1790
|
+
* 1. Routes whose `filePath` exactly matches.
|
|
1791
|
+
* 2. Among matches, prefer the one whose `locale` matches the file's locale
|
|
1792
|
+
* directory (e.g. `source/zh-CN/x.mdx` → locale `zh-CN`).
|
|
1793
|
+
* 3. If no locale match, fall back to the default locale (if i18n is enabled)
|
|
1794
|
+
* or the first match.
|
|
1795
|
+
*/
|
|
1796
|
+
function resolveRouteForFile(filePath, routes, defaultLocale) {
|
|
1797
|
+
const matches = routes.filter((r) => r.filePath === filePath);
|
|
1798
|
+
if (matches.length === 0) return void 0;
|
|
1799
|
+
if (matches.length === 1) return matches[0];
|
|
1800
|
+
const fileLocale = inferLocaleFromPath(filePath);
|
|
1801
|
+
if (fileLocale) {
|
|
1802
|
+
const localeMatch = matches.find((r) => r.locale === fileLocale);
|
|
1803
|
+
if (localeMatch) return localeMatch;
|
|
1804
|
+
}
|
|
1805
|
+
if (defaultLocale) {
|
|
1806
|
+
const defaultMatch = matches.find((r) => r.locale === defaultLocale);
|
|
1807
|
+
if (defaultMatch) return defaultMatch;
|
|
1808
|
+
}
|
|
1809
|
+
return matches[0];
|
|
1810
|
+
}
|
|
1811
|
+
/**
|
|
1812
|
+
* Derive a best-effort preview route for a file that is not in the route
|
|
1813
|
+
* manifest (e.g. a draft or newly created file). The path is computed from the
|
|
1814
|
+
* file's location relative to the content root, following the same convention
|
|
1815
|
+
* as route discovery (`source/{locale}/path/index.mdx` → `/{locale}/path`).
|
|
1816
|
+
*
|
|
1817
|
+
* Returns null when the file is outside the content root or is not a
|
|
1818
|
+
* recognized content file type.
|
|
1819
|
+
*/
|
|
1820
|
+
function inferRouteForFile(filePath, contentRoot, defaultLocale) {
|
|
1821
|
+
const ref = relative(contentRoot, filePath);
|
|
1822
|
+
if (!ref || ref.startsWith("..")) return null;
|
|
1823
|
+
const isMdx = /\.mdx?$/.test(filePath);
|
|
1824
|
+
const isOpenApi = /\.openapi\.(json|ya?ml)$/.test(filePath);
|
|
1825
|
+
if (!isMdx && !isOpenApi) return null;
|
|
1826
|
+
const segments = ref.split("/");
|
|
1827
|
+
const fileLocale = inferLocaleFromPath(filePath);
|
|
1828
|
+
const localeSegmentIndex = fileLocale ? segments.indexOf(fileLocale) : -1;
|
|
1829
|
+
const basePath = basePathFromRef(localeSegmentIndex >= 0 ? segments.slice(localeSegmentIndex + 1).join("/") : ref);
|
|
1830
|
+
const path = fileLocale && defaultLocale ? localizedRoutePath(basePath, fileLocale, {
|
|
1831
|
+
defaultLocale,
|
|
1832
|
+
missing: "fallback",
|
|
1833
|
+
locales: []
|
|
1834
|
+
}) : basePath;
|
|
1835
|
+
const title = segments[segments.length - 1]?.replace(/\.(mdx?|openapi\.(json|ya?ml))$/, "") || "Untitled";
|
|
1836
|
+
return {
|
|
1837
|
+
path: normalizePath(path),
|
|
1838
|
+
filePath,
|
|
1839
|
+
locale: fileLocale,
|
|
1840
|
+
basePath: normalizePath(basePath),
|
|
1841
|
+
kind: isMdx ? "mdx" : "openapi",
|
|
1842
|
+
title,
|
|
1843
|
+
inferred: true
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
/** Best-effort locale inference from a file path segment like `.../zh-CN/x.mdx`. */
|
|
1847
|
+
function inferLocaleFromPath(filePath) {
|
|
1848
|
+
const segments = filePath.split("/");
|
|
1849
|
+
for (const segment of segments) if (/^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2})?$/.test(segment)) return segment;
|
|
1850
|
+
}
|
|
1851
|
+
/** Read and parse the JSON body of an IncomingMessage. */
|
|
1852
|
+
function readJsonBody(req) {
|
|
1853
|
+
return new Promise((resolveBody, reject) => {
|
|
1854
|
+
const chunks = [];
|
|
1855
|
+
req.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
1856
|
+
req.on("error", reject);
|
|
1857
|
+
req.on("end", () => {
|
|
1858
|
+
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
1859
|
+
if (!raw) return resolveBody({});
|
|
1860
|
+
try {
|
|
1861
|
+
resolveBody(JSON.parse(raw));
|
|
1862
|
+
} catch (err) {
|
|
1863
|
+
reject(err);
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Handle a request to the dev route endpoint. Pure function — does not touch
|
|
1870
|
+
* the network directly, only reads the request body and writes to `res`.
|
|
1871
|
+
*/
|
|
1872
|
+
async function handleDevRouteRequest(req, res, routes, projectConfig, contentRoot) {
|
|
1873
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
1874
|
+
let body;
|
|
1875
|
+
try {
|
|
1876
|
+
body = await readJsonBody(req);
|
|
1877
|
+
} catch {
|
|
1878
|
+
res.statusCode = 400;
|
|
1879
|
+
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
const file = typeof body === "object" && body !== null ? body.file : void 0;
|
|
1883
|
+
if (typeof file === "string" && file.length > 0) {
|
|
1884
|
+
const route = resolveRouteForFile(file, routes, projectConfig.i18n?.defaultLocale);
|
|
1885
|
+
if (route) {
|
|
1886
|
+
res.end(JSON.stringify(toDevRouteEntry(route)));
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
const inferred = inferRouteForFile(file, contentRoot, projectConfig.i18n?.defaultLocale);
|
|
1890
|
+
res.end(JSON.stringify(inferred));
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
res.end(JSON.stringify(routes.map(toDevRouteEntry)));
|
|
1894
|
+
}
|
|
1775
1895
|
//#endregion
|
|
1776
1896
|
//#region source/core/env-types.ts
|
|
1777
1897
|
var GENERATED_FILE_NAME = "clarify-env.d.ts";
|
|
@@ -1831,6 +1951,84 @@ function resolveBuildOptions(options = {}) {
|
|
|
1831
1951
|
};
|
|
1832
1952
|
}
|
|
1833
1953
|
//#endregion
|
|
1954
|
+
//#region source/core/user-config.ts
|
|
1955
|
+
function defineConfig(config) {
|
|
1956
|
+
validateProjectConfig(config);
|
|
1957
|
+
return config;
|
|
1958
|
+
}
|
|
1959
|
+
/**
|
|
1960
|
+
* Config filenames Clarify CLI looks for at the project root, in resolution
|
|
1961
|
+
* order. Exported so other modules (e.g. the dev `project-info` endpoint) can
|
|
1962
|
+
* surface the same list to tooling without duplicating it.
|
|
1963
|
+
*/
|
|
1964
|
+
var CONFIG_FILENAMES = [
|
|
1965
|
+
"clarify.ts",
|
|
1966
|
+
"clarify.js",
|
|
1967
|
+
"clarify.json"
|
|
1968
|
+
];
|
|
1969
|
+
function findClarifyConfigFile(root) {
|
|
1970
|
+
for (const filename of CONFIG_FILENAMES) {
|
|
1971
|
+
const filePath = resolve(root, filename);
|
|
1972
|
+
if (existsSync(filePath)) return filePath;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
function assertConfigObject(config, configFile) {
|
|
1976
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) throw new Error(`[clarify] ${configFile} must export a configuration object`);
|
|
1977
|
+
return config;
|
|
1978
|
+
}
|
|
1979
|
+
function loadJsonConfig(configFile) {
|
|
1980
|
+
const config = assertConfigObject(JSON.parse(readFileSync(configFile, "utf-8")), configFile);
|
|
1981
|
+
const projectConfig = validateProjectConfig(config);
|
|
1982
|
+
const ssg = config.ssg && typeof config.ssg === "object" && !Array.isArray(config.ssg) ? config.ssg : void 0;
|
|
1983
|
+
return {
|
|
1984
|
+
...projectConfig,
|
|
1985
|
+
...ssg ? { ssg } : {}
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1988
|
+
async function loadClarifyConfig(root, env) {
|
|
1989
|
+
const configFile = findClarifyConfigFile(root);
|
|
1990
|
+
if (!configFile) return {};
|
|
1991
|
+
if (configFile.endsWith(".json")) return loadJsonConfig(configFile);
|
|
1992
|
+
return assertConfigObject((await loadConfigFromFile(env, configFile, root, "silent"))?.config, configFile);
|
|
1993
|
+
}
|
|
1994
|
+
/**
|
|
1995
|
+
* File extensions Clarify treats as content files. Kept in sync with the
|
|
1996
|
+
* patterns used by route discovery in `parsers/routes.ts` and the OpenAPI
|
|
1997
|
+
* page generator. Exposed to tooling so the extension's "is this a content
|
|
1998
|
+
* file?" check stays accurate without duplicating the regex.
|
|
1999
|
+
*/
|
|
2000
|
+
var CONTENT_FILE_EXTENSIONS = [
|
|
2001
|
+
".md",
|
|
2002
|
+
".mdx",
|
|
2003
|
+
".openapi.json",
|
|
2004
|
+
".openapi.yaml",
|
|
2005
|
+
".openapi.yml"
|
|
2006
|
+
];
|
|
2007
|
+
/**
|
|
2008
|
+
* Build the project-info response payload from the resolved plugin state.
|
|
2009
|
+
*/
|
|
2010
|
+
function buildProjectInfo(projectRoot, contentRoot, projectConfig) {
|
|
2011
|
+
const response = {
|
|
2012
|
+
configFilenames: CONFIG_FILENAMES,
|
|
2013
|
+
contentFileExtensions: CONTENT_FILE_EXTENSIONS,
|
|
2014
|
+
contentRoot: (contentRoot.startsWith(projectRoot) ? contentRoot.slice(projectRoot.length).replace(/^[/\\]+/, "") : contentRoot) || "source",
|
|
2015
|
+
projectRoot
|
|
2016
|
+
};
|
|
2017
|
+
if (projectConfig.i18n) response.i18n = {
|
|
2018
|
+
defaultLocale: projectConfig.i18n.defaultLocale,
|
|
2019
|
+
locales: projectConfig.i18n.locales.map((l) => l.code)
|
|
2020
|
+
};
|
|
2021
|
+
return response;
|
|
2022
|
+
}
|
|
2023
|
+
/**
|
|
2024
|
+
* Handle a request to the project-info endpoint. Responds to any method
|
|
2025
|
+
* (GET is typical) with the JSON payload — there is no request body to parse.
|
|
2026
|
+
*/
|
|
2027
|
+
function handleProjectInfoRequest(_req, res, projectRoot, contentRoot, projectConfig) {
|
|
2028
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
2029
|
+
res.end(JSON.stringify(buildProjectInfo(projectRoot, contentRoot, projectConfig)));
|
|
2030
|
+
}
|
|
2031
|
+
//#endregion
|
|
1834
2032
|
//#region source/core/site.ts
|
|
1835
2033
|
async function discoverRoutesForRoot(routeRoot, locale, plugins, ctx) {
|
|
1836
2034
|
return (await runHooks(plugins, "routes:discover", {
|
|
@@ -2104,42 +2302,6 @@ async function renderSSGRoutes(routes, projectConfig, outputDirectory, ssrBundle
|
|
|
2104
2302
|
}
|
|
2105
2303
|
}
|
|
2106
2304
|
//#endregion
|
|
2107
|
-
//#region source/core/user-config.ts
|
|
2108
|
-
function defineConfig(config) {
|
|
2109
|
-
validateProjectConfig(config);
|
|
2110
|
-
return config;
|
|
2111
|
-
}
|
|
2112
|
-
var CONFIG_FILENAMES = [
|
|
2113
|
-
"clarify.ts",
|
|
2114
|
-
"clarify.js",
|
|
2115
|
-
"clarify.json"
|
|
2116
|
-
];
|
|
2117
|
-
function findClarifyConfigFile(root) {
|
|
2118
|
-
for (const filename of CONFIG_FILENAMES) {
|
|
2119
|
-
const filePath = resolve(root, filename);
|
|
2120
|
-
if (existsSync(filePath)) return filePath;
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
function assertConfigObject(config, configFile) {
|
|
2124
|
-
if (!config || typeof config !== "object" || Array.isArray(config)) throw new Error(`[clarify] ${configFile} must export a configuration object`);
|
|
2125
|
-
return config;
|
|
2126
|
-
}
|
|
2127
|
-
function loadJsonConfig(configFile) {
|
|
2128
|
-
const config = assertConfigObject(JSON.parse(readFileSync(configFile, "utf-8")), configFile);
|
|
2129
|
-
const projectConfig = validateProjectConfig(config);
|
|
2130
|
-
const ssg = config.ssg && typeof config.ssg === "object" && !Array.isArray(config.ssg) ? config.ssg : void 0;
|
|
2131
|
-
return {
|
|
2132
|
-
...projectConfig,
|
|
2133
|
-
...ssg ? { ssg } : {}
|
|
2134
|
-
};
|
|
2135
|
-
}
|
|
2136
|
-
async function loadClarifyConfig(root, env) {
|
|
2137
|
-
const configFile = findClarifyConfigFile(root);
|
|
2138
|
-
if (!configFile) return {};
|
|
2139
|
-
if (configFile.endsWith(".json")) return loadJsonConfig(configFile);
|
|
2140
|
-
return assertConfigObject((await loadConfigFromFile(env, configFile, root, "silent"))?.config, configFile);
|
|
2141
|
-
}
|
|
2142
|
-
//#endregion
|
|
2143
2305
|
//#region source/core/plugin.ts
|
|
2144
2306
|
function loadVirtualModule(id, modules) {
|
|
2145
2307
|
const bareId = stripVirtualPrefix(id);
|
|
@@ -2287,6 +2449,11 @@ function clarifyPlugin(options = {}) {
|
|
|
2287
2449
|
async configureServer(server) {
|
|
2288
2450
|
server.watcher.add(contentRoot);
|
|
2289
2451
|
if (configFilePath) server.watcher.add(configFilePath);
|
|
2452
|
+
server.middlewares.use((req, res, next) => {
|
|
2453
|
+
if (req.url === "/dev/query-preview-route" && req.method === "POST") return handleDevRouteRequest(req, res, routes, projectConfig, contentRoot);
|
|
2454
|
+
if (req.url === "/dev/project-info" && (req.method === "GET" || req.method === "HEAD")) return handleProjectInfoRequest(req, res, root, contentRoot, projectConfig);
|
|
2455
|
+
next();
|
|
2456
|
+
});
|
|
2290
2457
|
const handleContentTreeChange = async (filePath) => {
|
|
2291
2458
|
const relativeContentFile = relative(contentRoot, isAbsolute(filePath) ? filePath : join(root, filePath));
|
|
2292
2459
|
if (!(relativeContentFile && !relativeContentFile.startsWith("..") && !isAbsolute(relativeContentFile))) return;
|
|
@@ -2368,6 +2535,6 @@ function clarifyPlugin(options = {}) {
|
|
|
2368
2535
|
].flat().filter(Boolean);
|
|
2369
2536
|
}
|
|
2370
2537
|
//#endregion
|
|
2371
|
-
export {
|
|
2538
|
+
export { loadClarifyConfig as a, defineConfig as i, createClarifyRuntimeAliases as n, createClarifyTempDir as o, resolveClarifySite as r, clarifyPlugin as t };
|
|
2372
2539
|
|
|
2373
|
-
//# sourceMappingURL=plugin-
|
|
2540
|
+
//# sourceMappingURL=plugin-_mqQSBqE.js.map
|