@shapeshift-labs/frontier-lang-cli 0.3.8 → 0.3.9
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/README.md +4 -1
- package/dist/index.js +114 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,6 +6,9 @@ Command line interface for parsing, checking, hashing, and emitting Frontier Lan
|
|
|
6
6
|
frontier-lang check app.frontier --strict-effects
|
|
7
7
|
frontier-lang emit app.frontier --target rust --out generated.rs
|
|
8
8
|
frontier-lang capabilities app.frontier --target typescript --platform node
|
|
9
|
+
frontier-lang import src/todo.ts --sidecar --out native-import.json
|
|
10
|
+
frontier-lang project-native native-import.json --source-only --out restored.ts
|
|
11
|
+
frontier-lang native-coverage src/todo.ts
|
|
9
12
|
```
|
|
10
13
|
|
|
11
14
|
## Related Packages
|
|
@@ -190,7 +193,7 @@ npm install -g @shapeshift-labs/frontier-lang-cli
|
|
|
190
193
|
frontier-lang check examples/todo.frontier
|
|
191
194
|
```
|
|
192
195
|
|
|
193
|
-
Commands: `parse`, `check`, `hash`, `ast`, `capabilities`, `to-json`, `from-json`, `import`, `roundtrip`, `corpus-roundtrip`, `emit`, `emit-ts`, `emit-js`, `emit-rust`, `emit-python`, and `emit-c`.
|
|
196
|
+
Commands: `parse`, `check`, `hash`, `ast`, `capabilities`, `to-json`, `from-json`, `import`, `project-native`, `native-coverage`, `roundtrip`, `corpus-roundtrip`, `emit`, `emit-ts`, `emit-js`, `emit-rust`, `emit-python`, and `emit-c`.
|
|
194
197
|
|
|
195
198
|
```sh
|
|
196
199
|
frontier-lang emit app.frontier --target rust --out app.rs
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,12 @@ import { checkDocument } from '@shapeshift-labs/frontier-lang-checker';
|
|
|
7
7
|
import { hashDocumentBase } from '@shapeshift-labs/frontier-lang-kernel';
|
|
8
8
|
import {
|
|
9
9
|
compileFrontierDocument,
|
|
10
|
+
createNativeSourcePreservation,
|
|
11
|
+
createNativeImportCoverageMatrix,
|
|
12
|
+
createSemanticImportSidecar,
|
|
10
13
|
createUniversalAstFromDocument,
|
|
11
14
|
importNativeSource,
|
|
15
|
+
projectNativeImportToSource,
|
|
12
16
|
projectFrontierAst,
|
|
13
17
|
readUniversalAstJson,
|
|
14
18
|
resolveCapabilityAdapters,
|
|
@@ -31,15 +35,28 @@ export async function runCli(argv = process.argv.slice(2), io = console) {
|
|
|
31
35
|
return io.log(result.output);
|
|
32
36
|
}
|
|
33
37
|
if (command === 'import') {
|
|
38
|
+
const imported = importNativeFile(file, source, rest);
|
|
39
|
+
if (rest.includes('--sidecar-only')) return outputMaybeFile(io, rest, createSemanticImportSidecar(imported));
|
|
40
|
+
if (rest.includes('--sidecar')) {
|
|
41
|
+
return outputMaybeFile(io, rest, { import: imported, sidecar: createSemanticImportSidecar(imported) });
|
|
42
|
+
}
|
|
43
|
+
return outputMaybeFile(io, rest, imported);
|
|
44
|
+
}
|
|
45
|
+
if (command === 'project-native') {
|
|
46
|
+
const imported = readNativeImportForProjection(file, source, rest);
|
|
47
|
+
const projection = projectNativeImportToSource(imported, { preferPreservedSource: !rest.includes('--stubs') });
|
|
48
|
+
if (rest.includes('--source-only')) {
|
|
49
|
+
const outIndex = rest.indexOf('--out');
|
|
50
|
+
if (outIndex >= 0 && rest[outIndex + 1]) writeFileSync(rest[outIndex + 1], projection.sourceText);
|
|
51
|
+
else io.log(projection.sourceText);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
return outputMaybeFile(io, rest, projection);
|
|
55
|
+
}
|
|
56
|
+
if (command === 'native-coverage') {
|
|
34
57
|
const language = readOption(rest, '--language') ?? inferLanguage(file);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
parser: readOption(rest, '--parser'),
|
|
38
|
-
sourcePath: file,
|
|
39
|
-
sourceHash: readOption(rest, '--source-hash'),
|
|
40
|
-
sourceText: source,
|
|
41
|
-
nativeAstMetadata: { sourceBytes: source.length }
|
|
42
|
-
}));
|
|
58
|
+
const imported = importNativeFile(file, source, rest, { language });
|
|
59
|
+
return outputMaybeFile(io, rest, createNativeImportCoverageMatrix({ imports: [imported] }));
|
|
43
60
|
}
|
|
44
61
|
const document = file ? parseFrontierFile(file, source) : parseFrontierSource(source);
|
|
45
62
|
if (command === 'to-json') {
|
|
@@ -111,6 +128,11 @@ function runCorpusRoundtrip(inputPath, args) {
|
|
|
111
128
|
failed: failed.length,
|
|
112
129
|
sourceMapCount: files.reduce((sum, fileResult) => sum + (fileResult.sourceMapCount ?? 0), 0),
|
|
113
130
|
lossCount: files.reduce((sum, fileResult) => sum + (fileResult.lossCount ?? 0), 0),
|
|
131
|
+
sourcePreservationCount: files.filter((fileResult) => fileResult.sourcePreservationId).length,
|
|
132
|
+
projectionModes: files.reduce((counts, fileResult) => {
|
|
133
|
+
if (fileResult.projectionMode) counts[fileResult.projectionMode] = (counts[fileResult.projectionMode] ?? 0) + 1;
|
|
134
|
+
return counts;
|
|
135
|
+
}, {}),
|
|
114
136
|
readiness: files.reduce((counts, fileResult) => {
|
|
115
137
|
for (const readiness of fileResult.mergeReadiness ?? []) counts[readiness] = (counts[readiness] ?? 0) + 1;
|
|
116
138
|
return counts;
|
|
@@ -152,6 +174,7 @@ function corpusRoundtripFile(entry, options) {
|
|
|
152
174
|
sourcePath: path,
|
|
153
175
|
sourceText: source
|
|
154
176
|
});
|
|
177
|
+
const projection = projectNativeImportToSource(imported);
|
|
155
178
|
const encoded = writeUniversalAstJson(imported.universalAst);
|
|
156
179
|
const decoded = readUniversalAstJson(encoded);
|
|
157
180
|
return {
|
|
@@ -165,6 +188,11 @@ function corpusRoundtripFile(entry, options) {
|
|
|
165
188
|
evidenceCount: imported.evidence?.length ?? 0,
|
|
166
189
|
symbolCount: imported.semanticIndex?.symbols?.length ?? 0,
|
|
167
190
|
occurrenceCount: imported.semanticIndex?.occurrences?.length ?? 0,
|
|
191
|
+
sourcePreservationId: imported.metadata?.sourcePreservationId,
|
|
192
|
+
sourcePreservationExact: imported.metadata?.sourcePreservation?.summary?.exactSourceAvailable === true,
|
|
193
|
+
projectionMode: projection.mode,
|
|
194
|
+
projectionReadiness: projection.readiness?.readiness,
|
|
195
|
+
projectionLossCount: projection.losses?.length ?? 0,
|
|
168
196
|
mergeReadiness: (imported.mergeCandidates ?? []).map((candidate) => candidate.readiness),
|
|
169
197
|
jsonBytes: encoded.length
|
|
170
198
|
};
|
|
@@ -217,6 +245,68 @@ function readCorpusManifest(path) {
|
|
|
217
245
|
});
|
|
218
246
|
}
|
|
219
247
|
|
|
248
|
+
function importNativeFile(file, source, args, defaults = {}) {
|
|
249
|
+
const language = defaults.language ?? readOption(args, '--language') ?? inferLanguage(file);
|
|
250
|
+
const sourceHash = readOption(args, '--source-hash');
|
|
251
|
+
const sourcePreservation = sourcePreservationOptionsRequested(args)
|
|
252
|
+
? createNativeSourcePreservation({
|
|
253
|
+
language,
|
|
254
|
+
sourcePath: file,
|
|
255
|
+
sourceHash,
|
|
256
|
+
sourceText: source,
|
|
257
|
+
includeSourceText: !args.includes('--omit-source-text'),
|
|
258
|
+
includeTokens: !args.includes('--no-tokens'),
|
|
259
|
+
includeTrivia: !args.includes('--no-trivia'),
|
|
260
|
+
includeDirectives: !args.includes('--no-directives'),
|
|
261
|
+
maxTokens: readIntegerOption(args, '--max-tokens'),
|
|
262
|
+
maxTrivia: readIntegerOption(args, '--max-trivia'),
|
|
263
|
+
maxDirectives: readIntegerOption(args, '--max-directives'),
|
|
264
|
+
metadata: { cli: true }
|
|
265
|
+
})
|
|
266
|
+
: undefined;
|
|
267
|
+
return importNativeSource({
|
|
268
|
+
language,
|
|
269
|
+
parser: readOption(args, '--parser'),
|
|
270
|
+
sourcePath: file,
|
|
271
|
+
sourceHash,
|
|
272
|
+
sourceText: source,
|
|
273
|
+
sourcePreservation,
|
|
274
|
+
nativeAstMetadata: { sourceBytes: source.length }
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function readNativeImportForProjection(file, source, args) {
|
|
279
|
+
const parsed = tryParseJson(source);
|
|
280
|
+
if (!parsed) return importNativeFile(file, source, args);
|
|
281
|
+
if (parsed.kind === 'frontier.lang.universalAst') {
|
|
282
|
+
const nativeSource = parsed.nativeSources?.[0];
|
|
283
|
+
return {
|
|
284
|
+
id: parsed.metadata?.nativeImportId ?? `import_${idFragment(parsed.id)}`,
|
|
285
|
+
language: parsed.metadata?.sourceLanguage ?? nativeSource?.language ?? readOption(args, '--language') ?? inferLanguage(file),
|
|
286
|
+
sourcePath: parsed.metadata?.sourcePath ?? nativeSource?.sourcePath,
|
|
287
|
+
universalAst: parsed,
|
|
288
|
+
nativeSource,
|
|
289
|
+
nativeAst: nativeSource?.ast,
|
|
290
|
+
semanticIndex: parsed.semanticIndex,
|
|
291
|
+
sourceMaps: parsed.sourceMaps,
|
|
292
|
+
losses: parsed.losses,
|
|
293
|
+
evidence: parsed.evidence,
|
|
294
|
+
metadata: parsed.metadata ?? {}
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
return parsed;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function tryParseJson(source) {
|
|
301
|
+
const trimmed = source.trim();
|
|
302
|
+
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return undefined;
|
|
303
|
+
try {
|
|
304
|
+
return JSON.parse(trimmed);
|
|
305
|
+
} catch {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
220
310
|
function isIgnoredCorpusDirectory(name) {
|
|
221
311
|
return name === 'node_modules' || name === '.git' || name === 'dist' || name === 'coverage' || name === '.next';
|
|
222
312
|
}
|
|
@@ -229,8 +319,23 @@ function idFragment(value) {
|
|
|
229
319
|
return String(value ?? 'unknown').replace(/[^A-Za-z0-9]+/g, '_').replace(/^_+|_+$/g, '').toLowerCase() || 'unknown';
|
|
230
320
|
}
|
|
231
321
|
|
|
232
|
-
function help(io) { io.log('frontier-lang <parse|check|hash|ast|capabilities|to-json|from-json|import|roundtrip|corpus-roundtrip|emit|emit-ts|emit-js|emit-rust|emit-python|emit-c> <file> [--target target] [--language language] [--parser parser] [--platform platform] [--ast] [--out file] [--strict-effects]'); }
|
|
322
|
+
function help(io) { io.log('frontier-lang <parse|check|hash|ast|capabilities|to-json|from-json|import|project-native|native-coverage|roundtrip|corpus-roundtrip|emit|emit-ts|emit-js|emit-rust|emit-python|emit-c> <file> [--target target] [--language language] [--parser parser] [--platform platform] [--ast] [--sidecar] [--sidecar-only] [--source-only] [--stubs] [--out file] [--strict-effects]'); }
|
|
233
323
|
function readOption(args, flag) { const index = args.indexOf(flag); return index >= 0 ? args[index + 1] : undefined; }
|
|
324
|
+
function readIntegerOption(args, flag) {
|
|
325
|
+
const value = readOption(args, flag);
|
|
326
|
+
if (value === undefined) return undefined;
|
|
327
|
+
const parsed = Number.parseInt(value, 10);
|
|
328
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
329
|
+
}
|
|
330
|
+
function sourcePreservationOptionsRequested(args) {
|
|
331
|
+
return args.includes('--omit-source-text')
|
|
332
|
+
|| args.includes('--no-tokens')
|
|
333
|
+
|| args.includes('--no-trivia')
|
|
334
|
+
|| args.includes('--no-directives')
|
|
335
|
+
|| args.includes('--max-tokens')
|
|
336
|
+
|| args.includes('--max-trivia')
|
|
337
|
+
|| args.includes('--max-directives');
|
|
338
|
+
}
|
|
234
339
|
function inferLanguage(file) {
|
|
235
340
|
if (!file) return 'unknown';
|
|
236
341
|
if (/\.[cm]?tsx?$/.test(file)) return 'typescript';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shapeshift-labs/frontier-lang-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Command line interface for parsing, checking, hashing, and emitting Frontier Lang projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@shapeshift-labs/frontier-lang-checker": "0.3.3",
|
|
57
|
-
"@shapeshift-labs/frontier-lang-compiler": "0.2.
|
|
57
|
+
"@shapeshift-labs/frontier-lang-compiler": "0.2.10",
|
|
58
58
|
"@shapeshift-labs/frontier-lang-kernel": "0.3.3",
|
|
59
59
|
"@shapeshift-labs/frontier-lang-parser": "0.3.3"
|
|
60
60
|
},
|