@hydranium/cli 1.0.0-next.117 → 1.0.0-next.123
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/commands/init-templates.js +5 -5
- package/lib/commands/save.d.ts +5 -0
- package/lib/commands/save.d.ts.map +1 -1
- package/lib/commands/save.js +29 -4
- package/lib/commands/save.js.map +1 -1
- package/package.json +9 -9
- package/src/commands/init-templates.ts +5 -5
- package/src/commands/save.ts +45 -4
|
@@ -743,9 +743,9 @@ const SERIALIZER = `// Concrete-syntax emitter for __GRAMMAR__ — the parser's
|
|
|
743
743
|
//
|
|
744
744
|
// Without it every structured write fails: the framework's default binding at
|
|
745
745
|
// \`services.serializer.Serializer\` THROWS, because a concrete syntax is
|
|
746
|
-
// language knowledge no framework can derive. \`
|
|
747
|
-
// the data head's \`saveModelDocument\` and a GLSP \`SaveModelAction\`
|
|
748
|
-
// it.
|
|
746
|
+
// language knowledge no framework can derive. A client session's \`update\` /
|
|
747
|
+
// \`save\`, the data head's \`saveModelDocument\` and a GLSP \`SaveModelAction\`
|
|
748
|
+
// all reach it.
|
|
749
749
|
//
|
|
750
750
|
// \`AbstractSerializer\`'s generic property walk lays out FORMAT-structured
|
|
751
751
|
// output — its YAML and JSON subclasses are what it exists for — and cannot
|
|
@@ -1172,8 +1172,8 @@ function serializationTest(composition) {
|
|
|
1172
1172
|
const transferTypes = composition.grammars.map(grammar => `${grammar.entryRule} as Transfer${grammar.entryRule}`);
|
|
1173
1173
|
const text = `// Round-trips each grammar through its serializer: parse the source, serialize
|
|
1174
1174
|
// the model, compare the text. The serializer is the parser's inverse, so this
|
|
1175
|
-
// is the assertion that keeps \`
|
|
1176
|
-
// language server can read back.
|
|
1175
|
+
// is the assertion that keeps a client session's \`update\` / \`save\` writing
|
|
1176
|
+
// files the language server can read back.
|
|
1177
1177
|
//
|
|
1178
1178
|
// The transfer case is the one that catches the mistake worth catching.
|
|
1179
1179
|
// \`ModelService.modelToText\` short-circuits only a RAW STRING, so a typed model
|
package/lib/commands/save.d.ts
CHANGED
|
@@ -18,6 +18,11 @@ import type { DataServerProtocol } from '@hydranium/protocol/data';
|
|
|
18
18
|
*
|
|
19
19
|
* `clientId` defaults to `'hydranium-cli'` — adopters wanting a richer
|
|
20
20
|
* identity (per-user, per-script) override.
|
|
21
|
+
*
|
|
22
|
+
* The command saves as a client session under `clientId`: it registers the
|
|
23
|
+
* session, creates the document from the content when there is no file,
|
|
24
|
+
* opens it otherwise, saves, and ends the session, which leaves nothing open
|
|
25
|
+
* behind it.
|
|
21
26
|
*/
|
|
22
27
|
export interface SaveCommandOptions {
|
|
23
28
|
readonly serverCommand: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../src/commands/save.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAKnE
|
|
1
|
+
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../src/commands/save.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAKnE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,kBAAkB;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAC9D,sFAAsF;IACtF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACjE;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBxE"}
|
package/lib/commands/save.js
CHANGED
|
@@ -14,8 +14,7 @@ export async function runSave(options) {
|
|
|
14
14
|
const clientId = options.clientId ?? 'hydranium-cli';
|
|
15
15
|
const model = await resolveContent(options.content, options.__readFileForTest);
|
|
16
16
|
if (options.__proxyForTest) {
|
|
17
|
-
|
|
18
|
-
write(`${JSON.stringify(doc)}\n`);
|
|
17
|
+
write(`${JSON.stringify(await saveOpened(options.__proxyForTest, options.uri, clientId, model))}\n`);
|
|
19
18
|
return;
|
|
20
19
|
}
|
|
21
20
|
await withDataServer({
|
|
@@ -24,10 +23,36 @@ export async function runSave(options) {
|
|
|
24
23
|
cwd: options.cwd,
|
|
25
24
|
env: options.logLevel ? logLevelEnv(options.logLevel) : undefined
|
|
26
25
|
}, async (server) => {
|
|
27
|
-
|
|
28
|
-
write(`${JSON.stringify(doc)}\n`);
|
|
26
|
+
write(`${JSON.stringify(await saveOpened(server, options.uri, clientId, model))}\n`);
|
|
29
27
|
});
|
|
30
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Save `model` to `uri` as the session `clientId`, and end the session whether
|
|
31
|
+
* the save succeeded or not. An end that fails after a failed save is
|
|
32
|
+
* swallowed: the save's error is the one the user needs.
|
|
33
|
+
*/
|
|
34
|
+
async function saveOpened(server, uri, clientId, model) {
|
|
35
|
+
await server.createSession({ clientId, label: 'hydranium-cli' });
|
|
36
|
+
let saved;
|
|
37
|
+
try {
|
|
38
|
+
// The server creates a document only when it finds no file and no
|
|
39
|
+
// client has it open; anything else is opened. An open that fails
|
|
40
|
+
// reports why the create failed too, since that may be the real cause.
|
|
41
|
+
await server.createModelDocument({ uri, clientId, text: model }).catch((created) => server.openModelDocument({ uri, clientId }).catch((opened) => {
|
|
42
|
+
throw new Error(`Cannot save ${uri}: ${describe(opened)} (creating it failed first: ${describe(created)})`, { cause: created });
|
|
43
|
+
}));
|
|
44
|
+
saved = await server.saveModelDocument({ uri, clientId, model, basedOn: 'anything' });
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
await server.closeSession({ clientId }).catch(() => undefined);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
await server.closeSession({ clientId });
|
|
51
|
+
return saved;
|
|
52
|
+
}
|
|
53
|
+
function describe(error) {
|
|
54
|
+
return error instanceof Error ? error.message : String(error);
|
|
55
|
+
}
|
|
31
56
|
/**
|
|
32
57
|
* Resolve the `--content` argument to its textual form. The `@<path>`
|
|
33
58
|
* prefix reads from a file (parses as UTF-8); anything else is taken
|
package/lib/commands/save.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save.js","sourceRoot":"","sources":["../../src/commands/save.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"save.js","sourceRoot":"","sources":["../../src/commands/save.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hydranium/cli",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.123",
|
|
4
4
|
"description": "Build-time codegen tools + data-server subcommands for the hydranium framework.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hydranium",
|
|
@@ -65,20 +65,20 @@
|
|
|
65
65
|
"ts-morph": "^25.0.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@hydranium/core": "1.0.0-next.
|
|
69
|
-
"@hydranium/data-server": "1.0.0-next.
|
|
70
|
-
"@hydranium/langium": "1.0.0-next.
|
|
71
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
68
|
+
"@hydranium/core": "1.0.0-next.123",
|
|
69
|
+
"@hydranium/data-server": "1.0.0-next.123",
|
|
70
|
+
"@hydranium/langium": "1.0.0-next.123",
|
|
71
|
+
"@hydranium/protocol": "1.0.0-next.123",
|
|
72
72
|
"rimraf": "^5.0.0",
|
|
73
73
|
"typescript": "^5.8.0",
|
|
74
74
|
"vscode-jsonrpc": "9.0.1",
|
|
75
75
|
"vscode-languageserver": "~10.0.1"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
|
-
"@hydranium/core": "1.0.0-next.
|
|
79
|
-
"@hydranium/data-server": "1.0.0-next.
|
|
80
|
-
"@hydranium/langium": "1.0.0-next.
|
|
81
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
78
|
+
"@hydranium/core": "1.0.0-next.123",
|
|
79
|
+
"@hydranium/data-server": "1.0.0-next.123",
|
|
80
|
+
"@hydranium/langium": "1.0.0-next.123",
|
|
81
|
+
"@hydranium/protocol": "1.0.0-next.123",
|
|
82
82
|
"@memlab/core": "^2.0.3",
|
|
83
83
|
"@memlab/heap-analysis": "^2.0.3",
|
|
84
84
|
"vscode-jsonrpc": "9.0.1"
|
|
@@ -809,9 +809,9 @@ const SERIALIZER = `// Concrete-syntax emitter for __GRAMMAR__ — the parser's
|
|
|
809
809
|
//
|
|
810
810
|
// Without it every structured write fails: the framework's default binding at
|
|
811
811
|
// \`services.serializer.Serializer\` THROWS, because a concrete syntax is
|
|
812
|
-
// language knowledge no framework can derive. \`
|
|
813
|
-
// the data head's \`saveModelDocument\` and a GLSP \`SaveModelAction\`
|
|
814
|
-
// it.
|
|
812
|
+
// language knowledge no framework can derive. A client session's \`update\` /
|
|
813
|
+
// \`save\`, the data head's \`saveModelDocument\` and a GLSP \`SaveModelAction\`
|
|
814
|
+
// all reach it.
|
|
815
815
|
//
|
|
816
816
|
// \`AbstractSerializer\`'s generic property walk lays out FORMAT-structured
|
|
817
817
|
// output — its YAML and JSON subclasses are what it exists for — and cannot
|
|
@@ -1260,8 +1260,8 @@ function serializationTest(composition: InitComposition): string {
|
|
|
1260
1260
|
const transferTypes = composition.grammars.map(grammar => `${grammar.entryRule} as Transfer${grammar.entryRule}`);
|
|
1261
1261
|
const text = `// Round-trips each grammar through its serializer: parse the source, serialize
|
|
1262
1262
|
// the model, compare the text. The serializer is the parser's inverse, so this
|
|
1263
|
-
// is the assertion that keeps \`
|
|
1264
|
-
// language server can read back.
|
|
1263
|
+
// is the assertion that keeps a client session's \`update\` / \`save\` writing
|
|
1264
|
+
// files the language server can read back.
|
|
1265
1265
|
//
|
|
1266
1266
|
// The transfer case is the one that catches the mistake worth catching.
|
|
1267
1267
|
// \`ModelService.modelToText\` short-circuits only a RAW STRING, so a typed model
|
package/src/commands/save.ts
CHANGED
|
@@ -23,6 +23,11 @@ import { withDataServer } from '../spawn-data-server.js';
|
|
|
23
23
|
*
|
|
24
24
|
* `clientId` defaults to `'hydranium-cli'` — adopters wanting a richer
|
|
25
25
|
* identity (per-user, per-script) override.
|
|
26
|
+
*
|
|
27
|
+
* The command saves as a client session under `clientId`: it registers the
|
|
28
|
+
* session, creates the document from the content when there is no file,
|
|
29
|
+
* opens it otherwise, saves, and ends the session, which leaves nothing open
|
|
30
|
+
* behind it.
|
|
26
31
|
*/
|
|
27
32
|
export interface SaveCommandOptions {
|
|
28
33
|
readonly serverCommand: string;
|
|
@@ -46,8 +51,7 @@ export async function runSave(options: SaveCommandOptions): Promise<void> {
|
|
|
46
51
|
const model = await resolveContent(options.content, options.__readFileForTest);
|
|
47
52
|
|
|
48
53
|
if (options.__proxyForTest) {
|
|
49
|
-
|
|
50
|
-
write(`${JSON.stringify(doc)}\n`);
|
|
54
|
+
write(`${JSON.stringify(await saveOpened(options.__proxyForTest, options.uri, clientId, model))}\n`);
|
|
51
55
|
return;
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -59,12 +63,49 @@ export async function runSave(options: SaveCommandOptions): Promise<void> {
|
|
|
59
63
|
env: options.logLevel ? logLevelEnv(options.logLevel) : undefined
|
|
60
64
|
},
|
|
61
65
|
async server => {
|
|
62
|
-
|
|
63
|
-
write(`${JSON.stringify(doc)}\n`);
|
|
66
|
+
write(`${JSON.stringify(await saveOpened(server, options.uri, clientId, model))}\n`);
|
|
64
67
|
}
|
|
65
68
|
);
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Save `model` to `uri` as the session `clientId`, and end the session whether
|
|
73
|
+
* the save succeeded or not. An end that fails after a failed save is
|
|
74
|
+
* swallowed: the save's error is the one the user needs.
|
|
75
|
+
*/
|
|
76
|
+
async function saveOpened(
|
|
77
|
+
server: Pick<
|
|
78
|
+
DataServerProtocol<TransferElement>,
|
|
79
|
+
'createSession' | 'openModelDocument' | 'createModelDocument' | 'saveModelDocument' | 'closeSession'
|
|
80
|
+
>,
|
|
81
|
+
uri: string,
|
|
82
|
+
clientId: string,
|
|
83
|
+
model: string
|
|
84
|
+
): Promise<unknown> {
|
|
85
|
+
await server.createSession({ clientId, label: 'hydranium-cli' });
|
|
86
|
+
let saved: unknown;
|
|
87
|
+
try {
|
|
88
|
+
// The server creates a document only when it finds no file and no
|
|
89
|
+
// client has it open; anything else is opened. An open that fails
|
|
90
|
+
// reports why the create failed too, since that may be the real cause.
|
|
91
|
+
await server.createModelDocument({ uri, clientId, text: model }).catch((created: unknown) =>
|
|
92
|
+
server.openModelDocument({ uri, clientId }).catch((opened: unknown) => {
|
|
93
|
+
throw new Error(`Cannot save ${uri}: ${describe(opened)} (creating it failed first: ${describe(created)})`, { cause: created });
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
saved = await server.saveModelDocument({ uri, clientId, model, basedOn: 'anything' });
|
|
97
|
+
} catch (error: unknown) {
|
|
98
|
+
await server.closeSession({ clientId }).catch(() => undefined);
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
await server.closeSession({ clientId });
|
|
102
|
+
return saved;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function describe(error: unknown): string {
|
|
106
|
+
return error instanceof Error ? error.message : String(error);
|
|
107
|
+
}
|
|
108
|
+
|
|
68
109
|
/**
|
|
69
110
|
* Resolve the `--content` argument to its textual form. The `@<path>`
|
|
70
111
|
* prefix reads from a file (parses as UTF-8); anything else is taken
|