1 | "use strict";
|
2 |
|
3 | const
|
4 | ToloframeworkPermissiveJson = require( "toloframework-permissive-json" ),
|
5 | Preprocessor = require( "./boilerplate.preprocessor" ),
|
6 | Fatal = require( "./fatal" ),
|
7 | View = require( "./boilerplate.view" ),
|
8 | Global = require( "./boilerplate.global" );
|
9 |
|
10 |
|
11 | const codeGenerators = { View, Global };
|
12 |
|
13 |
|
14 | exports.registerCodeGenerator = function ( name, generator ) {
|
15 | codeGenerators[ name ] = generator;
|
16 | };
|
17 |
|
18 |
|
19 | exports.generateCodeFrom = function ( src ) {
|
20 | const xjs = src.clone( "xjs" );
|
21 | if ( xjs.exists() === false ) return src.read();
|
22 |
|
23 | try {
|
24 | const
|
25 | rawDef = parseXJS( xjs ),
|
26 | def = Preprocessor( rawDef ),
|
27 | boilerplate = codeGenerators[ def[ 0 ] ];
|
28 |
|
29 | if ( !boilerplate ) {
|
30 | throw Error( `Unknown code generator "${def[0]}"!\n` +
|
31 | `Available generators are: ${Object.keys(codeGenerators).join(", ")}.` );
|
32 | }
|
33 | return boilerplate.generateCodeFrom( def, src.read(), src.name() );
|
34 | } catch ( ex ) {
|
35 | Fatal.fire(
|
36 | `Fatal error in ${xjs.getAbsoluteFilePath()}!\n${ex}`,
|
37 | src.name(),
|
38 | xjs.getAbsoluteFilePath()
|
39 | );
|
40 | }
|
41 | return null;
|
42 | };
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | function parseXJS( xjs ) {
|
49 | const xjsFileContent = xjs.read();
|
50 | try {
|
51 | return ToloframeworkPermissiveJson.parse( xjsFileContent );
|
52 | } catch ( ex ) {
|
53 | const code = getFewLinesOfCode( xjsFileContent, ex.index, 3 );
|
54 | throw Error( `Invalid permissive JSON syntax:${ex.message}\n\n${code}` );
|
55 | }
|
56 | }
|
57 |
|
58 |
|
59 | function getFewLinesOfCode( code, issuePosition, linesToDisplay ) {
|
60 | if ( typeof linesToDisplay === 'undefined' ) linesToDisplay = 3;
|
61 | var lineCount = 1;
|
62 | var currentIndex = 0;
|
63 | var previousIndex = 0;
|
64 | var lines = [];
|
65 | issuePosition = Math.min( issuePosition, code.length - 1 );
|
66 | while ( currentIndex < code.length ) {
|
67 | if ( code.charAt( currentIndex ) === '\n' ) {
|
68 | lines.push( { line: lineCount, begin: previousIndex, end: currentIndex } );
|
69 | if ( lines.length > linesToDisplay )
|
70 | lines.shift();
|
71 | previousIndex = currentIndex + 1;
|
72 | lineCount++;
|
73 | if ( currentIndex >= issuePosition ) break;
|
74 | }
|
75 | currentIndex++;
|
76 | }
|
77 |
|
78 | debugger;
|
79 | var columnsSeparator = ": ";
|
80 | var lineNumbersLengths = lines.map( x => ( "" + x.line ).length );
|
81 | var spaceForLineNumbers = lineNumbersLengths.reduce( ( a, v ) => Math.max( a, v ), 0 );
|
82 | var output = lines.map(
|
83 | x => padStart( x.line, spaceForLineNumbers ) +
|
84 | columnsSeparator + code.substring( x.begin, x.end ) ).join( "\n" );
|
85 | var lastLineBegin = lines.pop().begin;
|
86 | output += "\n" + padStart( "^",
|
87 | spaceForLineNumbers + columnsSeparator.length + issuePosition - lastLineBegin - 1 );
|
88 | return output;
|
89 | }
|
90 |
|
91 | function padStart( text, targetLength, padString ) {
|
92 | if ( typeof padString === 'undefined' ) padString = ' ';
|
93 | text = "" + text;
|
94 | while ( text.length < targetLength )
|
95 | text = padString + text;
|
96 | return text;
|
97 | } |
\ | No newline at end of file |