Skip to content

Commit b7f1679

Browse files
committed
Merge remote-tracking branch 'origin/master' into elm-references-to-guida
Conflicts: src/Node/Format.elm
2 parents 86a7d28 + 8689b74 commit b7f1679

29 files changed

+249
-1007
lines changed

.github/pull_request_template.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ Briefly describe the goal of this pull request and what problem it solves.
1616
- [ ] The code compiles and all tests pass (`npm test`)
1717
- [ ] The change has been tested in:
1818
- [ ] CLI
19-
- [ ] Browser
20-
- [ ] Node (API)
19+
- [ ] API
2120
- [ ] I’ve added or updated tests, if applicable
2221
- [ ] I’ve updated relevant documentation or comments
2322
- [ ] My changes follow the project's coding style

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
cache: "npm"
2323
- run: npm ci
2424
- run: npm run build:bin
25-
- run: npm run build:browser
25+
- run: npm run build:api
2626
- run: npm run test:eslint
2727
- run: npm run test:elm-format-validate
2828
- run: npm run test:jest

.gitignore

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@ elm-stuff
77
guida-stuff
88

99
# Main
10-
lib/guida.node.js
11-
lib/guida.node.min.js
12-
13-
# Browser
14-
lib/guida.browser.js
15-
lib/guida.browser.min.js
10+
lib/guida.js
11+
lib/guida.min.js
1612

1713
# Command line
1814
bin/guida.js

.npmignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
bin/guida.js
33
elm-stuff
44
examples
5-
lib/guida.node.js
6-
lib/guida.browser.js
5+
lib/guida.js
76
guida-stuff
87
review
98
scripts

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ For detailed instructions on setting up your environment for contributing to Gui
6767
We aim for stability and consistency. If you’re adding features or fixing bugs, please:
6868

6969
- Write tests if applicable.
70-
- Consider all 3 outputs of the project: bin (command line), browser and node (API).
70+
- Consider both outputs of the project: bin (command line) and API (browser and node).
7171
- Make sure to test all three output targets of the project:
7272
- CLI (bin) — the command-line interface
7373
- Browser — compiled for browser usage

eslint.config.mjs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,15 @@ export default defineConfig([
88
globalIgnores([
99
"bin/guida.js",
1010
"bin/guida.min.js",
11-
"lib/guida.browser.js",
12-
"lib/guida.browser.min.js",
13-
"lib/guida.node.js",
14-
"lib/guida.node.min.js",
11+
"lib/guida.js",
12+
"lib/guida.min.js",
1513
"elm-stuff",
1614
"guida-stuff",
1715
]),
1816
{ files: ["**/*.{js,mjs,cjs}"] },
1917
{ files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } },
2018
{ files: ["bin/**/*.{js,mjs,cjs}"], languageOptions: { globals: globals.node } },
21-
{ files: ["lib/browser.js"], languageOptions: { globals: globals.browser } },
22-
{ files: ["lib/node.js"], languageOptions: { globals: globals.node } },
19+
{ files: ["lib/index.js"], languageOptions: { globals: { ...globals.browser, ...globals.node } } },
2320
{ files: ["try/**/*.{js,mjs,cjs}"], languageOptions: { globals: { ...globals.browser, ...globals.node } } },
2421
{ files: ["scripts/*.js"], languageOptions: { globals: globals.node } },
2522
{

lib/index.d.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Configuration object expected by the Guida runner.
3+
*/
4+
export interface GuidaConfig {
5+
// XMLHttpRequest constructor for making HTTP requests.
6+
XMLHttpRequest: typeof XMLHttpRequest;
7+
8+
// Write text or binary data to a path.
9+
writeFile(path: string, data: string | ArrayBuffer | Uint8Array | Buffer): Promise<void>;
10+
11+
// Read file contents. Can return text or binary data.
12+
readFile(path: string): Promise<string | ArrayBuffer | Uint8Array | Buffer | { buffer: ArrayBuffer }>;
13+
14+
// Read a directory and return a list of files.
15+
readDirectory(path: string): Promise<{ files: string[] }>;
16+
17+
// Create a directory.
18+
createDirectory(path: string): Promise<void>;
19+
20+
// Get details for a path (file or directory).
21+
details(path: string): Promise<{ type: 'file' | 'directory' | string; createdAt?: number }>;
22+
23+
// Returns the current working directory.
24+
getCurrentDirectory(): Promise<string>;
25+
26+
// Returns the string path of the current user's home directory.
27+
homedir(): Promise<string>;
28+
29+
// Environment map used by the runner.
30+
env?: Record<string, any>;
31+
}
32+
33+
export interface MakeOptions {
34+
debug?: boolean;
35+
optimize?: boolean;
36+
sourcemaps?: boolean;
37+
}
38+
39+
// The runtime returns various JSON-able responses. Keep this generic to reflect the dynamic
40+
// nature of the results coming from the embedded Elm/runner process.
41+
export type GuidaResponse = any;
42+
43+
declare const _default: {
44+
make: (config: GuidaConfig, path: string, options?: MakeOptions) => Promise<GuidaResponse>;
45+
format: (config: GuidaConfig, content: string) => Promise<GuidaResponse>;
46+
install: (config: GuidaConfig, pkg: string) => Promise<GuidaResponse>;
47+
uninstall: (config: GuidaConfig, pkg: string) => Promise<GuidaResponse>;
48+
diagnostics: (config: GuidaConfig, args: { content: string } | { path: string }) => Promise<{ errors?: any }>;
49+
};
50+
51+
export default _default;

lib/browser.js renamed to lib/index.js

Lines changed: 46 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
1-
const { createFs } = require("indexeddb-fs");
21
const { newServer } = require("mock-xmlhttprequest");
32
const JSZip = require("jszip");
43

5-
const savedXMLHttpRequest = globalThis.XMLHttpRequest;
6-
const fs = createFs({ databaseName: "guida-fs" });
7-
8-
const runGuida = function (extraEnv, args) {
4+
const runGuida = function (config, args) {
95
return new Promise((resolve) => {
106
let mVarsNextCounter = 0;
117
const mVars = {};
128
const lockedFiles = {};
139

14-
const env = Object.assign({
15-
GUIDA_HOME: "root/.guida",
16-
}, extraEnv);
17-
1810
const download = function (method, url) {
1911
const that = this;
2012

21-
const xhr = new savedXMLHttpRequest();
13+
const xhr = new config.XMLHttpRequest();
2214
xhr.open(method, url, true);
2315
xhr.responseType = "arraybuffer";
2416

@@ -85,16 +77,15 @@ const runGuida = function (extraEnv, args) {
8577
server.post("writeString", async (request) => {
8678
const path = request.requestHeaders.getHeader("path");
8779

88-
await fs.writeFile(path, request.body);
80+
await config.writeFile(path, request.body);
8981
request.respond(200);
9082
});
9183

9284
server.post("read", async (request) => {
93-
const content = await fs.readFile(request.body);
85+
const content = await config.readFile(request.body);
9486
request.respond(200, null, content);
9587
});
9688

97-
9889
server.post("getArchive", (request) => {
9990
download.apply({
10091
send: ({ sha, archive }) => {
@@ -105,8 +96,7 @@ const runGuida = function (extraEnv, args) {
10596

10697
server.post("dirDoesFileExist", async (request) => {
10798
try {
108-
const stats = await fs.details(request.body);
109-
console.log("dirDoesFileExist", request.body, stats);
99+
const stats = await config.details(request.body);
110100
request.respond(200, null, stats.type === "file");
111101
} catch (_err) {
112102
request.respond(200, null, false);
@@ -116,19 +106,20 @@ const runGuida = function (extraEnv, args) {
116106
server.post("dirCreateDirectoryIfMissing", async (request) => {
117107
const { createParents, filename } = JSON.parse(request.body);
118108
let directories = [filename];
109+
let prefix = filename.startsWith("/") ? "/" : "";
119110

120111
if (createParents) {
121112
directories = filename.split('/').filter(Boolean);
122-
directories = directories.map((_, index) => directories.slice(0, index + 1).join('/'));
113+
directories = directories.map((_, index) => prefix + directories.slice(0, index + 1).join('/'));
123114
}
124115

125116
await directories.reduce(async (previousPromise, directory) => {
126117
await previousPromise;
127118

128119
try {
129-
await fs.details(directory);
120+
await config.details(directory);
130121
} catch (_err) {
131-
await fs.createDirectory(directory);
122+
await config.createDirectory(directory);
132123
}
133124
}, Promise.resolve());
134125

@@ -165,13 +156,13 @@ const runGuida = function (extraEnv, args) {
165156
});
166157

167158
server.post("dirGetModificationTime", async (request) => {
168-
const stats = await fs.details(request.body);
159+
const stats = await config.details(request.body);
169160
request.respond(200, null, stats.createdAt);
170161
});
171162

172163
server.post("dirDoesDirectoryExist", async (request) => {
173164
try {
174-
const stats = await fs.details(request.body);
165+
const stats = await config.details(request.body);
175166
request.respond(200, null, stats.type === "directory");
176167
} catch (_err) {
177168
request.respond(200, null, false);
@@ -183,33 +174,35 @@ const runGuida = function (extraEnv, args) {
183174
});
184175

185176
server.post("dirListDirectory", async (request) => {
186-
const { files } = await fs.readDirectory(request.body);
177+
const { files } = await config.readDirectory(request.body);
187178
request.respond(200, null, JSON.stringify(files));
188179
});
189180

190181
server.post("binaryDecodeFileOrFail", async (request) => {
191-
const data = await fs.readFile(request.body);
182+
const data = await config.readFile(request.body);
192183
request.respond(200, null, data.buffer);
193184
});
194185

195186
server.post("write", async (request) => {
196187
const path = request.requestHeaders.getHeader("path");
197188

198-
await fs.writeFile(path, request.body);
189+
await config.writeFile(path, request.body);
199190
request.respond(200);
200191
});
201192

202-
server.post("dirGetCurrentDirectory", (request) => {
203-
request.respond(200, null, "root");
193+
server.post("dirGetCurrentDirectory", async (request) => {
194+
const currentDir = await config.getCurrentDirectory();
195+
request.respond(200, null, currentDir);
204196
});
205197

206198
server.post("envLookupEnv", (request) => {
207-
const envVar = env[request.body] ?? null;
199+
const envVar = config.env[request.body] ?? null;
208200
request.respond(200, null, JSON.stringify(envVar));
209201
});
210202

211-
server.post("dirGetAppUserDataDirectory", (request) => {
212-
request.respond(200, null, `root/.${request.body}`);
203+
server.post("dirGetAppUserDataDirectory", async (request) => {
204+
const homedir = await config.homedir();
205+
request.respond(200, null, `${homedir}/.${request.body}`);
213206
});
214207

215208
// MVARS
@@ -282,7 +275,7 @@ const runGuida = function (extraEnv, args) {
282275
}
283276
});
284277

285-
// BROWSER
278+
// API
286279
server.post("getArgs", (request) => {
287280
request.respond(200, null, JSON.stringify(args));
288281
});
@@ -297,11 +290,9 @@ const runGuida = function (extraEnv, args) {
297290
});
298291

299292
server.setDefaultHandler((request) => {
300-
console.log("defaultHandler", request.url);
301-
302293
const headers = request.requestHeaders.getHash();
303294

304-
var xhr = new savedXMLHttpRequest();
295+
var xhr = new config.XMLHttpRequest();
305296
xhr.open(request.method, request.url, true);
306297

307298
for (const key in headers) {
@@ -317,63 +308,32 @@ const runGuida = function (extraEnv, args) {
317308

318309
server.install();
319310

320-
const { Elm } = require("./guida.browser.min.js");
311+
const { Elm } = require("./guida.min.js");
321312

322-
Elm.Browser.Main.init();
313+
Elm.API.Main.init();
323314
});
324-
}
325-
326-
const elmJsonContent = `{
327-
"type": "application",
328-
"source-directories": [
329-
"src"
330-
],
331-
"elm-version": "0.19.1",
332-
"dependencies": {
333-
"direct": {
334-
"elm/browser": "1.0.2",
335-
"elm/core": "1.0.5",
336-
"elm/html": "1.0.0"
337-
},
338-
"indirect": {
339-
"elm/json": "1.1.3",
340-
"elm/time": "1.0.0",
341-
"elm/url": "1.0.0",
342-
"elm/virtual-dom": "1.0.3"
343-
}
344-
},
345-
"test-dependencies": {
346-
"direct": {},
347-
"indirect": {}
348-
}
349-
}`;
315+
};
350316

351317
module.exports = {
352-
init: async (extraEnv) => {
353-
await fs.writeFile("root/elm.json", elmJsonContent);
354-
await fs.createDirectory("root/src");
355-
356-
return {
357-
make: async (content, options) => {
358-
await fs.writeFile("root/src/Main.guida", content);
359-
360-
return await runGuida(extraEnv, {
361-
command: "make",
362-
path: "src/Main.guida",
363-
debug: !!options.debug,
364-
optimize: !!options.optimize,
365-
sourcemaps: !!options.sourcemaps
366-
});
367-
},
368-
format: async (content) => {
369-
return await runGuida(extraEnv, { command: "format", content });
370-
},
371-
install: async (pkg) => {
372-
return await runGuida(extraEnv, { command: "install", pkg });
373-
},
374-
uninstall: async (pkg) => {
375-
return await runGuida(extraEnv, { command: "uninstall", pkg });
376-
}
377-
};
318+
make: async (config, path, options) => {
319+
return await runGuida(config, {
320+
command: "make",
321+
path,
322+
debug: !!options.debug,
323+
optimize: !!options.optimize,
324+
sourcemaps: !!options.sourcemaps
325+
});
326+
},
327+
format: async (config, content) => {
328+
return await runGuida(config, { command: "format", content });
329+
},
330+
install: async (config, pkg) => {
331+
return await runGuida(config, { command: "install", pkg });
332+
},
333+
uninstall: async (config, pkg) => {
334+
return await runGuida(config, { command: "uninstall", pkg });
335+
},
336+
diagnostics: async (config, args) => {
337+
return await runGuida(config, { command: "diagnostics", ...args });
378338
}
379339
};

lib/node.d.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)