@olenbetong/appframe-vite 6.3.3 → 6.3.4
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/lib/cli-resources-add.js +3 -6
- package/lib/cli-resources-edit.js +3 -6
- package/lib/cli-resources-generate.js +5 -6
- package/lib/proxy.js +1 -1
- package/lib/resourceGenerate.d.ts +7 -0
- package/lib/resourceGenerate.js +59 -17
- package/lib/writeGeneratedFile.test.d.ts +1 -0
- package/lib/writeGeneratedFile.test.js +19 -0
- package/package.json +4 -4
package/lib/cli-resources-add.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname, relative, resolve } from "node:path";
|
|
1
|
+
import { relative, resolve } from "node:path";
|
|
3
2
|
import { Client, generateApiDataHandler } from "@olenbetong/appframe-data";
|
|
4
3
|
import { config } from "dotenv";
|
|
5
4
|
import fuzzy from "fuzzy";
|
|
6
5
|
import inquirer from "inquirer";
|
|
7
6
|
import autocomplete from "inquirer-autocomplete-standalone";
|
|
8
7
|
import { getLoginInfo } from "./devServer.js";
|
|
9
|
-
import { fetchAndGenerate, fetchResourceDefinition,
|
|
8
|
+
import { fetchAndGenerate, fetchResourceDefinition, writeGeneratedFile } from "./resourceGenerate.js";
|
|
10
9
|
import { entryToCLIOptions, readResourcesConfig, writeResourcesConfig } from "./resourcesConfig.js";
|
|
11
10
|
config({ quiet: true });
|
|
12
11
|
async function getResources(client) {
|
|
@@ -185,8 +184,6 @@ export async function addResource() {
|
|
|
185
184
|
options.output = resolve(process.cwd(), output);
|
|
186
185
|
let content = await fetchAndGenerate(chosenResource, options, client);
|
|
187
186
|
let outputPath = resolve(process.cwd(), output);
|
|
188
|
-
await
|
|
189
|
-
await writeFile(outputPath, content, "utf-8");
|
|
190
|
-
await formatWithBiome(outputPath);
|
|
187
|
+
await writeGeneratedFile(outputPath, content);
|
|
191
188
|
console.log(`Generated ${output}`);
|
|
192
189
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname, relative, resolve } from "node:path";
|
|
1
|
+
import { relative, resolve } from "node:path";
|
|
3
2
|
import { Client } from "@olenbetong/appframe-data";
|
|
4
3
|
import { config } from "dotenv";
|
|
5
4
|
import fuzzy from "fuzzy";
|
|
6
5
|
import inquirer from "inquirer";
|
|
7
6
|
import autocomplete from "inquirer-autocomplete-standalone";
|
|
8
7
|
import { getLoginInfo } from "./devServer.js";
|
|
9
|
-
import { fetchAndGenerate, fetchResourceDefinition,
|
|
8
|
+
import { fetchAndGenerate, fetchResourceDefinition, writeGeneratedFile } from "./resourceGenerate.js";
|
|
10
9
|
import { entryToCLIOptions, readResourcesConfig, writeResourcesConfig } from "./resourcesConfig.js";
|
|
11
10
|
config({ quiet: true });
|
|
12
11
|
export async function editResource(id) {
|
|
@@ -178,8 +177,6 @@ export async function editResource(id) {
|
|
|
178
177
|
options.output = resolve(process.cwd(), output);
|
|
179
178
|
let content = await fetchAndGenerate(entry.resource, options, client);
|
|
180
179
|
let outputPath = resolve(process.cwd(), output);
|
|
181
|
-
await
|
|
182
|
-
await writeFile(outputPath, content, "utf-8");
|
|
183
|
-
await formatWithBiome(outputPath);
|
|
180
|
+
await writeGeneratedFile(outputPath, content);
|
|
184
181
|
console.log(`Regenerated ${output}`);
|
|
185
182
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
1
|
import { dirname, relative, resolve, sep } from "node:path";
|
|
3
2
|
import { Client } from "@olenbetong/appframe-data";
|
|
4
3
|
import { config } from "dotenv";
|
|
5
4
|
import { getLoginInfo } from "./devServer.js";
|
|
6
|
-
import { fetchAndGenerate,
|
|
5
|
+
import { fetchAndGenerate, writeGeneratedFile } from "./resourceGenerate.js";
|
|
7
6
|
import { entryToCLIOptions, readResourcesConfig } from "./resourcesConfig.js";
|
|
8
7
|
config({ quiet: true });
|
|
9
8
|
/**
|
|
@@ -49,10 +48,10 @@ export async function generateFromConfig(configPath) {
|
|
|
49
48
|
try {
|
|
50
49
|
let content = await fetchAndGenerate(entry.resource, options, client);
|
|
51
50
|
let outputPath = resolve(process.cwd(), entry.output ?? `src/data/${entry.id}.ts`);
|
|
52
|
-
await
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
let wroteFile = await writeGeneratedFile(outputPath, content);
|
|
52
|
+
if (wroteFile) {
|
|
53
|
+
console.log(` ✓ ${entry.id} → ${entry.output}`);
|
|
54
|
+
}
|
|
56
55
|
}
|
|
57
56
|
catch (error) {
|
|
58
57
|
let message = error?.message ?? String(error);
|
package/lib/proxy.js
CHANGED
|
@@ -144,7 +144,7 @@ export async function login(hostname, username, password, loginOptions) {
|
|
|
144
144
|
if (!silent) {
|
|
145
145
|
write(`\r${initialLogMessage}`);
|
|
146
146
|
}
|
|
147
|
-
//
|
|
147
|
+
// oxlint-disable-next-line no-control-regex -- is there another way?
|
|
148
148
|
let strippedInitialLogMessage = initialLogMessage.replace(/\u001b\[[0-9]+m/g, ""); // remove ANSI color codes for accurate cursor positioning
|
|
149
149
|
let initialCursorPos = strippedInitialLogMessage.length;
|
|
150
150
|
let start = performance.now();
|
|
@@ -5,6 +5,13 @@ import type { Client } from "@olenbetong/appframe-data";
|
|
|
5
5
|
* Silently skips if Biome is not found or formatting fails.
|
|
6
6
|
*/
|
|
7
7
|
export declare function formatWithBiome(filePath: string): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Write a generated file only when the content changed.
|
|
10
|
+
* Formats the content before comparing so that an already-formatted file
|
|
11
|
+
* on disk is not considered changed.
|
|
12
|
+
* Returns `true` when the file was written, `false` when it already matched.
|
|
13
|
+
*/
|
|
14
|
+
export declare function writeGeneratedFile(filePath: string, content: string): Promise<boolean>;
|
|
8
15
|
export type CLIOptions = {
|
|
9
16
|
server: string;
|
|
10
17
|
types?: boolean;
|
package/lib/resourceGenerate.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { exec } from "node:child_process";
|
|
1
|
+
import { exec, spawn } from "node:child_process";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
4
|
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
4
5
|
import { promisify } from "node:util";
|
|
5
6
|
import { importJson } from "./importJson.js";
|
|
@@ -7,31 +8,29 @@ const execAsync = promisify(exec);
|
|
|
7
8
|
// ---------------------------------------------------------------------------
|
|
8
9
|
// Biome formatting
|
|
9
10
|
// ---------------------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
* Format a file with Biome if available. Searches for `biome` in the nearest
|
|
12
|
-
* node_modules/.bin up from cwd, then falls back to the global PATH.
|
|
13
|
-
* Silently skips if Biome is not found or formatting fails.
|
|
14
|
-
*/
|
|
15
|
-
export async function formatWithBiome(filePath) {
|
|
16
|
-
let biomeBin = null;
|
|
11
|
+
function findBiomeBin() {
|
|
17
12
|
let current = resolve(process.cwd());
|
|
18
13
|
while (true) {
|
|
19
14
|
let candidate = join(current, "node_modules", ".bin", "biome");
|
|
20
15
|
let candidateCmd = `${candidate}.cmd`;
|
|
21
|
-
if (existsSync(candidateCmd))
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (existsSync(candidate)) {
|
|
26
|
-
biomeBin = candidate;
|
|
27
|
-
break;
|
|
28
|
-
}
|
|
16
|
+
if (existsSync(candidateCmd))
|
|
17
|
+
return candidateCmd;
|
|
18
|
+
if (existsSync(candidate))
|
|
19
|
+
return candidate;
|
|
29
20
|
let parent = dirname(current);
|
|
30
21
|
if (parent === current)
|
|
31
22
|
break;
|
|
32
23
|
current = parent;
|
|
33
24
|
}
|
|
34
|
-
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Format a file with Biome if available. Searches for `biome` in the nearest
|
|
29
|
+
* node_modules/.bin up from cwd, then falls back to the global PATH.
|
|
30
|
+
* Silently skips if Biome is not found or formatting fails.
|
|
31
|
+
*/
|
|
32
|
+
export async function formatWithBiome(filePath) {
|
|
33
|
+
let bin = findBiomeBin() ?? "biome";
|
|
35
34
|
try {
|
|
36
35
|
await execAsync(`"${bin}" format --write "${resolve(filePath)}"`);
|
|
37
36
|
}
|
|
@@ -39,6 +38,49 @@ export async function formatWithBiome(filePath) {
|
|
|
39
38
|
// Biome not available or not applicable — silently skip
|
|
40
39
|
}
|
|
41
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Format content in memory using Biome's stdin mode.
|
|
43
|
+
* Returns the formatted content, or the original if Biome is unavailable.
|
|
44
|
+
*/
|
|
45
|
+
async function formatContentWithBiome(content, filePath) {
|
|
46
|
+
let bin = findBiomeBin() ?? "biome";
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
let child = spawn(bin, ["format", `--stdin-file-path=${filePath}`], { stdio: "pipe" });
|
|
49
|
+
let stdout = "";
|
|
50
|
+
let failed = false;
|
|
51
|
+
child.stdout.on("data", (chunk) => {
|
|
52
|
+
stdout += chunk.toString();
|
|
53
|
+
});
|
|
54
|
+
child.on("error", () => {
|
|
55
|
+
failed = true;
|
|
56
|
+
resolve(content);
|
|
57
|
+
});
|
|
58
|
+
child.on("close", (code) => {
|
|
59
|
+
if (!failed)
|
|
60
|
+
resolve(code === 0 ? stdout : content);
|
|
61
|
+
});
|
|
62
|
+
child.stdin.write(content);
|
|
63
|
+
child.stdin.end();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Write a generated file only when the content changed.
|
|
68
|
+
* Formats the content before comparing so that an already-formatted file
|
|
69
|
+
* on disk is not considered changed.
|
|
70
|
+
* Returns `true` when the file was written, `false` when it already matched.
|
|
71
|
+
*/
|
|
72
|
+
export async function writeGeneratedFile(filePath, content) {
|
|
73
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
74
|
+
let formatted = await formatContentWithBiome(content, filePath);
|
|
75
|
+
if (existsSync(filePath)) {
|
|
76
|
+
let existing = await readFile(filePath, "utf-8");
|
|
77
|
+
if (existing === formatted) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
await writeFile(filePath, formatted, "utf-8");
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
42
84
|
// ---------------------------------------------------------------------------
|
|
43
85
|
// YAML config block
|
|
44
86
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { mkdtemp, readFile, rm, stat } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { writeGeneratedFile } from "./resourceGenerate.js";
|
|
6
|
+
describe("writeGeneratedFile", () => {
|
|
7
|
+
it("skips rewriting unchanged content", async () => {
|
|
8
|
+
let dir = await mkdtemp(join(tmpdir(), "appframe-vite-"));
|
|
9
|
+
let file = join(dir, "generated.ts");
|
|
10
|
+
expect(await writeGeneratedFile(file, "first")).toBe(true);
|
|
11
|
+
let firstContent = await readFile(file, "utf-8");
|
|
12
|
+
let firstMtime = (await stat(file)).mtimeMs;
|
|
13
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
14
|
+
expect(await writeGeneratedFile(file, "first")).toBe(false);
|
|
15
|
+
expect(await readFile(file, "utf-8")).toBe(firstContent);
|
|
16
|
+
expect((await stat(file)).mtimeMs).toBe(firstMtime);
|
|
17
|
+
await rm(dir, { recursive: true, force: true });
|
|
18
|
+
});
|
|
19
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olenbetong/appframe-vite",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.4",
|
|
4
4
|
"description": "Tools to use and deploy Vite applications to Appframe",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/jsdom": "^27.0.0",
|
|
48
|
-
"@types/node": "
|
|
49
|
-
"typescript": "
|
|
50
|
-
"vite": "8.
|
|
48
|
+
"@types/node": "26.1.1",
|
|
49
|
+
"typescript": "7.0.2",
|
|
50
|
+
"vite": "8.1.5"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"vite": ">=5.0.0"
|