@shapeshift-labs/frontier-lang-cli 0.3.6 → 0.3.8
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 +1 -1
- package/dist/index.js +141 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -190,7 +190,7 @@ npm install -g @shapeshift-labs/frontier-lang-cli
|
|
|
190
190
|
frontier-lang check examples/todo.frontier
|
|
191
191
|
```
|
|
192
192
|
|
|
193
|
-
Commands: `parse`, `check`, `hash`, `emit`, `emit-ts`, `emit-js`, `emit-rust`, `emit-python`, and `emit-c`.
|
|
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`.
|
|
194
194
|
|
|
195
195
|
```sh
|
|
196
196
|
frontier-lang emit app.frontier --target rust --out app.rs
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync, realpathSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { readdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
4
|
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import { parseFrontierFile, parseFrontierSource } from '@shapeshift-labs/frontier-lang-parser';
|
|
5
6
|
import { checkDocument } from '@shapeshift-labs/frontier-lang-checker';
|
|
@@ -18,6 +19,9 @@ export async function runCli(argv = process.argv.slice(2), io = console) {
|
|
|
18
19
|
const [command, file, ...rest] = argv;
|
|
19
20
|
if (!command || command === 'help' || command === '--help') return help(io);
|
|
20
21
|
if (!file && command !== 'version') throw new Error(`Missing input file for ${command}`);
|
|
22
|
+
if (command === 'corpus-roundtrip') {
|
|
23
|
+
return outputMaybeFile(io, rest, runCorpusRoundtrip(file, rest));
|
|
24
|
+
}
|
|
21
25
|
const source = file ? readFileSync(file, 'utf8') : '';
|
|
22
26
|
if (command === 'from-json') {
|
|
23
27
|
const envelope = readUniversalAstJson(source);
|
|
@@ -92,7 +96,140 @@ function outputMaybeFile(io, args, value) {
|
|
|
92
96
|
const outIndex = args.indexOf('--out');
|
|
93
97
|
if (outIndex >= 0 && args[outIndex + 1]) writeFileSync(args[outIndex + 1], json + '\n'); else io.log(json);
|
|
94
98
|
}
|
|
95
|
-
function
|
|
99
|
+
function runCorpusRoundtrip(inputPath, args) {
|
|
100
|
+
const target = readOption(args, '--target') ?? 'typescript';
|
|
101
|
+
const entries = collectCorpusEntries(inputPath);
|
|
102
|
+
const files = entries.map((entry) => corpusRoundtripFile(entry, { target, parser: readOption(args, '--parser') }));
|
|
103
|
+
const failed = files.filter((fileResult) => !fileResult.ok);
|
|
104
|
+
return {
|
|
105
|
+
kind: 'frontier.lang.corpusRoundtrip',
|
|
106
|
+
version: 1,
|
|
107
|
+
inputPath,
|
|
108
|
+
target,
|
|
109
|
+
total: files.length,
|
|
110
|
+
passed: files.length - failed.length,
|
|
111
|
+
failed: failed.length,
|
|
112
|
+
sourceMapCount: files.reduce((sum, fileResult) => sum + (fileResult.sourceMapCount ?? 0), 0),
|
|
113
|
+
lossCount: files.reduce((sum, fileResult) => sum + (fileResult.lossCount ?? 0), 0),
|
|
114
|
+
readiness: files.reduce((counts, fileResult) => {
|
|
115
|
+
for (const readiness of fileResult.mergeReadiness ?? []) counts[readiness] = (counts[readiness] ?? 0) + 1;
|
|
116
|
+
return counts;
|
|
117
|
+
}, {}),
|
|
118
|
+
files
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function corpusRoundtripFile(entry, options) {
|
|
123
|
+
const path = entry.path;
|
|
124
|
+
try {
|
|
125
|
+
const source = readFileSync(path, 'utf8');
|
|
126
|
+
const language = entry.language ?? inferLanguage(path);
|
|
127
|
+
if (/\.frontier$/i.test(path)) {
|
|
128
|
+
const document = parseFrontierFile(path, source);
|
|
129
|
+
const envelope = createUniversalAstFromDocument(document, {
|
|
130
|
+
evidence: [{ id: `frontier_lang_cli_corpus_${idFragment(path)}`, kind: 'test', status: 'passed', path, summary: 'Corpus Frontier source parsed into universal AST.' }]
|
|
131
|
+
});
|
|
132
|
+
const encoded = writeUniversalAstJson(envelope);
|
|
133
|
+
const decoded = readUniversalAstJson(encoded);
|
|
134
|
+
const result = compileFrontierDocument(decoded.document, { target: options.target });
|
|
135
|
+
return {
|
|
136
|
+
path,
|
|
137
|
+
language: 'frontier',
|
|
138
|
+
kind: 'frontierSource',
|
|
139
|
+
ok: result.ok && decoded.document.id === document.id,
|
|
140
|
+
hash: result.hash,
|
|
141
|
+
sourceMapCount: envelope.sourceMaps?.length ?? 0,
|
|
142
|
+
lossCount: envelope.losses?.length ?? 0,
|
|
143
|
+
evidenceCount: envelope.evidence?.length ?? 0,
|
|
144
|
+
diagnostics: result.diagnostics,
|
|
145
|
+
outputBytes: result.output.length,
|
|
146
|
+
jsonBytes: encoded.length
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const imported = importNativeSource({
|
|
150
|
+
language,
|
|
151
|
+
parser: entry.parser ?? options.parser,
|
|
152
|
+
sourcePath: path,
|
|
153
|
+
sourceText: source
|
|
154
|
+
});
|
|
155
|
+
const encoded = writeUniversalAstJson(imported.universalAst);
|
|
156
|
+
const decoded = readUniversalAstJson(encoded);
|
|
157
|
+
return {
|
|
158
|
+
path,
|
|
159
|
+
language,
|
|
160
|
+
kind: 'nativeSource',
|
|
161
|
+
ok: decoded.document.id === imported.document.id,
|
|
162
|
+
sourceMapCount: imported.sourceMaps?.length ?? 0,
|
|
163
|
+
sourceMapMappingCount: (imported.sourceMaps ?? []).reduce((sum, sourceMap) => sum + (sourceMap.mappings?.length ?? 0), 0),
|
|
164
|
+
lossCount: imported.losses?.length ?? 0,
|
|
165
|
+
evidenceCount: imported.evidence?.length ?? 0,
|
|
166
|
+
symbolCount: imported.semanticIndex?.symbols?.length ?? 0,
|
|
167
|
+
occurrenceCount: imported.semanticIndex?.occurrences?.length ?? 0,
|
|
168
|
+
mergeReadiness: (imported.mergeCandidates ?? []).map((candidate) => candidate.readiness),
|
|
169
|
+
jsonBytes: encoded.length
|
|
170
|
+
};
|
|
171
|
+
} catch (error) {
|
|
172
|
+
return {
|
|
173
|
+
path,
|
|
174
|
+
language: entry.language ?? inferLanguage(path),
|
|
175
|
+
kind: 'error',
|
|
176
|
+
ok: false,
|
|
177
|
+
error: error instanceof Error ? error.message : String(error)
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function collectCorpusEntries(inputPath) {
|
|
183
|
+
const absolute = resolve(inputPath);
|
|
184
|
+
const stat = statSync(absolute);
|
|
185
|
+
if (stat.isDirectory()) {
|
|
186
|
+
return collectCorpusDirectory(absolute).map((path) => ({ path }));
|
|
187
|
+
}
|
|
188
|
+
if (/\.json$/i.test(absolute)) {
|
|
189
|
+
return readCorpusManifest(absolute);
|
|
190
|
+
}
|
|
191
|
+
return [{ path: absolute }];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function collectCorpusDirectory(root) {
|
|
195
|
+
const files = [];
|
|
196
|
+
for (const item of readdirSync(root, { withFileTypes: true })) {
|
|
197
|
+
const path = join(root, item.name);
|
|
198
|
+
if (item.isDirectory()) {
|
|
199
|
+
if (!isIgnoredCorpusDirectory(item.name)) files.push(...collectCorpusDirectory(path));
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (item.isFile() && isCorpusSourceFile(path)) files.push(path);
|
|
203
|
+
}
|
|
204
|
+
return files.sort();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function readCorpusManifest(path) {
|
|
208
|
+
const manifest = JSON.parse(readFileSync(path, 'utf8'));
|
|
209
|
+
const base = dirname(path);
|
|
210
|
+
const rawEntries = Array.isArray(manifest) ? manifest : manifest.files ?? manifest.entries ?? [];
|
|
211
|
+
return rawEntries.map((entry) => {
|
|
212
|
+
if (typeof entry === 'string') return { path: resolve(base, entry) };
|
|
213
|
+
return {
|
|
214
|
+
...entry,
|
|
215
|
+
path: resolve(base, entry.path ?? entry.file)
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function isIgnoredCorpusDirectory(name) {
|
|
221
|
+
return name === 'node_modules' || name === '.git' || name === 'dist' || name === 'coverage' || name === '.next';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function isCorpusSourceFile(path) {
|
|
225
|
+
return /\.(frontier|[cm]?tsx?|m?jsx?|rs|py|c|h|hpp|cpp|cc|cxx|go|java|kt|cs|swift|php|rb|rake)$/i.test(path);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function idFragment(value) {
|
|
229
|
+
return String(value ?? 'unknown').replace(/[^A-Za-z0-9]+/g, '_').replace(/^_+|_+$/g, '').toLowerCase() || 'unknown';
|
|
230
|
+
}
|
|
231
|
+
|
|
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]'); }
|
|
96
233
|
function readOption(args, flag) { const index = args.indexOf(flag); return index >= 0 ? args[index + 1] : undefined; }
|
|
97
234
|
function inferLanguage(file) {
|
|
98
235
|
if (!file) return 'unknown';
|
|
@@ -107,6 +244,8 @@ function inferLanguage(file) {
|
|
|
107
244
|
if (/\.kt$/.test(file)) return 'kotlin';
|
|
108
245
|
if (/\.cs$/.test(file)) return 'csharp';
|
|
109
246
|
if (/\.swift$/.test(file)) return 'swift';
|
|
247
|
+
if (/\.php$/.test(file)) return 'php';
|
|
248
|
+
if (/\.rb$|\.rake$/.test(file)) return 'ruby';
|
|
110
249
|
return 'unknown';
|
|
111
250
|
}
|
|
112
251
|
|
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.8",
|
|
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",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"access": "public"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@shapeshift-labs/frontier-lang-checker": "0.3.
|
|
57
|
-
"@shapeshift-labs/frontier-lang-compiler": "0.2.
|
|
58
|
-
"@shapeshift-labs/frontier-lang-kernel": "0.3.
|
|
59
|
-
"@shapeshift-labs/frontier-lang-parser": "0.3.
|
|
56
|
+
"@shapeshift-labs/frontier-lang-checker": "0.3.3",
|
|
57
|
+
"@shapeshift-labs/frontier-lang-compiler": "0.2.7",
|
|
58
|
+
"@shapeshift-labs/frontier-lang-kernel": "0.3.3",
|
|
59
|
+
"@shapeshift-labs/frontier-lang-parser": "0.3.3"
|
|
60
60
|
},
|
|
61
61
|
"bin": {
|
|
62
62
|
"frontier-lang": "dist/index.js"
|