Some checks failed
Deploy Landing Page to Storj / deploy (push) Failing after 2s
Adds a first-class TypeScript code generator to speckl-compile that emits: - Const enum for workflow states (IssueWorkflowState) - Strongly-typed class with guards, state transitions, decision log - Proper this. prefixing (state vars only, not local params) - Enum references instead of string literals for state comparisons - Clean tsc --noEmit compilation Also includes: - specs/forgejo-issue-workflow.speckdl — full workflow with 9 actions, 8 constraints, 5 temporal verifications - Generator deduplication of duplicate AST nodes - Support for init block initialization of state variables The generator was validated against the Forgejo issue workflow spec, producing IssueWorkflow.ts that compiles with zero errors. Refs: heartbeat conversation re: speckl-compile extensibility
75 lines
No EOL
2.9 KiB
JavaScript
75 lines
No EOL
2.9 KiB
JavaScript
#!/usr/bin/env node
|
|
import yargs from 'yargs';
|
|
import { hideBin } from 'yargs/helpers';
|
|
import { parseSpeckFile } from './parser.js';
|
|
import { generateProvenanceGraph } from './generators/provenance.js';
|
|
import { generateCycloneDX } from './generators/cyclonedx.js';
|
|
import { generateSPDX } from './generators/spdx.js';
|
|
import { generateTypeScriptStateMachine } from './generators/typescript-state-machine.js';
|
|
import { generateWASM } from './generators/wasm.js';
|
|
import fs from 'fs';
|
|
async function main() {
|
|
const argv = await yargs(hideBin(process.argv))
|
|
.command('$0 <file>', 'Compile a SpeckDL specification', (yargsCmd) => {
|
|
return yargsCmd
|
|
.positional('file', {
|
|
describe: 'SpeckDL file to compile',
|
|
type: 'string',
|
|
demandOption: true,
|
|
})
|
|
.option('output-dir', {
|
|
alias: 'o',
|
|
describe: 'Output directory for compiled artifacts',
|
|
type: 'string',
|
|
default: './out',
|
|
})
|
|
.option('bom-format', {
|
|
alias: 'b',
|
|
describe: 'BOM output format',
|
|
type: 'string',
|
|
choices: ['cdx', 'spdx', 'both'],
|
|
default: 'both',
|
|
});
|
|
})
|
|
.help()
|
|
.argv;
|
|
const file = argv.file;
|
|
const options = {
|
|
outputDir: argv.outputDir,
|
|
bomFormat: argv.bomFormat,
|
|
};
|
|
console.log(`Compiling ${file}...`);
|
|
// Parse the Speck file
|
|
const ast = parseSpeckFile(file);
|
|
const speckCount = ast.specks.length;
|
|
const memberCount = ast.specks.reduce((sum, s) => sum + s.members.length, 0);
|
|
console.log(`AST parsed successfully: ${speckCount} speck(s), ${memberCount} member(s)`);
|
|
// Ensure output directory exists
|
|
if (!fs.existsSync(options.outputDir)) {
|
|
fs.mkdirSync(options.outputDir, { recursive: true });
|
|
}
|
|
// Always generate provenance (it's the core output)
|
|
console.log('\nGenerating provenance graph (PROV-O JSON-LD)...');
|
|
generateProvenanceGraph(ast, options.outputDir);
|
|
// Generate TypeScript state machine
|
|
console.log('\nGenerating TypeScript state machine...');
|
|
generateTypeScriptStateMachine(ast, options.outputDir);
|
|
// Generate WASM state machine
|
|
console.log('\nGenerating WebAssembly (WAT)...');
|
|
generateWASM(ast, options.outputDir);
|
|
// Generate BOM based on format selection
|
|
if (options.bomFormat === 'cdx' || options.bomFormat === 'both') {
|
|
console.log('\nGenerating CycloneDX BOM...');
|
|
generateCycloneDX(ast, options.outputDir);
|
|
}
|
|
if (options.bomFormat === 'spdx' || options.bomFormat === 'both') {
|
|
console.log('\nGenerating SPDX BOM...');
|
|
generateSPDX(ast, options.outputDir);
|
|
}
|
|
console.log(`\nCompilation complete. Output: ${options.outputDir}/`);
|
|
}
|
|
main().catch((err) => {
|
|
console.error('Compilation failed:', err);
|
|
process.exit(1);
|
|
});
|
|
//# sourceMappingURL=index.js.map
|