@sasjs/cli 6.27.3 → 6.29.0

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.
@@ -486,44 +486,276 @@ describe('service worker host', function () {
486
486
  });
487
487
  }); });
488
488
  it('answers only the line the interface writes, not one further down', function () { return __awaiter(void 0, void 0, void 0, function () {
489
- var worker, response, _a;
490
- var _b, _c;
491
- return __generator(this, function (_d) {
492
- switch (_d.label) {
489
+ var worker, response, body;
490
+ var _a, _b;
491
+ return __generator(this, function (_c) {
492
+ switch (_c.label) {
493
493
  case 0:
494
494
  // The interface puts `%let _program` first; a line further down belongs to
495
- // the program. Answered, it would hand a caller's own SAS program the session
496
- // recorded for another file - the "inventing a session" the refusal exists to
497
- // avoid, with a different file's log.
495
+ // the program. Reading it would hand a caller's own SAS program the session
496
+ // recorded for another file - a different file's log, which is worse than the
497
+ // mocked one.
498
498
  ;
499
- global.__sasTranscript = (_b = {},
500
- _b["".concat(appLoc, "/services/public/program.sas")] = {
499
+ global.__sasTranscript = (_a = {},
500
+ _a["".concat(appLoc, "/services/public/program.sas")] = {
501
501
  webout: '{"SYSSITE":"00000000"}',
502
502
  log: 'NOTE: recorded',
503
503
  print: 'The SAS System'
504
504
  },
505
- _b);
505
+ _a);
506
506
  worker = loadWorker();
507
- worker.runtime.load((_c = {},
508
- _c[drivePath('services/public/mine.sas')] = 'data work.class; run;',
509
- _c));
507
+ worker.runtime.load((_b = {},
508
+ _b[drivePath('services/public/mine.sas')] = 'data work.class; run;',
509
+ _b));
510
510
  return [4 /*yield*/, worker.dispatch('/SASjsApi/code/execute', runRequest({
511
511
  code: "data _null_;\n%let _program = ".concat(appLoc, "/services/public/program.sas;\nrun;"),
512
512
  runTime: 'sas'
513
513
  }))];
514
514
  case 1:
515
- response = _d.sent();
516
- expect(response.status).toBe(400);
517
- _a = expect;
515
+ response = _c.sent();
516
+ expect(response.status).toBe(200);
517
+ return [4 /*yield*/, response.text()];
518
+ case 2:
519
+ body = _c.sent();
520
+ expect(body).toContain('This is a mocked SAS session');
521
+ expect(body).not.toContain('NOTE: recorded');
522
+ delete global.__sasTranscript;
523
+ return [2 /*return*/];
524
+ }
525
+ });
526
+ }); });
527
+ it('answers a program it never recorded with the mocked session', function () { return __awaiter(void 0, void 0, void 0, function () {
528
+ var worker, response, body;
529
+ var _a;
530
+ return __generator(this, function (_b) {
531
+ switch (_b.label) {
532
+ case 0:
533
+ worker = loadWorker();
534
+ worker.runtime.load((_a = {},
535
+ _a[drivePath('services/public/other.sas')] = 'data work.class; run;',
536
+ _a));
537
+ return [4 /*yield*/, worker.dispatch('/SASjsApi/stp/execute?_program=' +
538
+ encodeURIComponent("".concat(appLoc, "/services/public/other")) +
539
+ '&_debug=131')];
540
+ case 1:
541
+ response = _b.sent();
542
+ expect(response.status).toBe(200);
543
+ return [4 /*yield*/, response.text()];
544
+ case 2:
545
+ body = _b.sent();
546
+ expect(body).toContain('This is a mocked SAS session');
547
+ expect(body).toContain('services/public/other');
548
+ expect(body).not.toContain('SAS is not available');
549
+ return [2 /*return*/];
550
+ }
551
+ });
552
+ }); });
553
+ it('answers an unsaved buffer with the mocked session', function () { return __awaiter(void 0, void 0, void 0, function () {
554
+ var worker, response, body;
555
+ return __generator(this, function (_a) {
556
+ switch (_a.label) {
557
+ case 0:
558
+ worker = loadWorker();
559
+ return [4 /*yield*/, worker.dispatch('/SASjsApi/code/execute', runRequest({ code: 'data work.class; run;', runTime: 'sas' }))];
560
+ case 1:
561
+ response = _a.sent();
562
+ expect(response.status).toBe(200);
563
+ return [4 /*yield*/, response.text()];
564
+ case 2:
565
+ body = _a.sent();
566
+ expect(body).toContain('This is a mocked SAS session');
567
+ expect(body).toContain('the code in this buffer');
568
+ return [2 /*return*/];
569
+ }
570
+ });
571
+ }); });
572
+ it('gives the mocked session the notes, warnings and errors a log panel reads', function () { return __awaiter(void 0, void 0, void 0, function () {
573
+ var worker, response, body;
574
+ return __generator(this, function (_a) {
575
+ switch (_a.label) {
576
+ case 0:
577
+ worker = loadWorker();
578
+ return [4 /*yield*/, worker.dispatch('/SASjsApi/code/execute', runRequest({ code: 'data work.class; run;', runTime: 'sas' }))];
579
+ case 1:
580
+ response = _a.sent();
581
+ return [4 /*yield*/, response.text()];
582
+ case 2:
583
+ body = _a.sent();
584
+ expect(body).toMatch(/^\d+\s+\w/m); // source lines with their numbers
585
+ expect(body).toContain('ERROR 22-322');
586
+ expect(body).toContain('WARNING:');
587
+ expect(body).toContain('NOTE:');
588
+ expect(body).toContain('The SAS System');
589
+ return [2 /*return*/];
590
+ }
591
+ });
592
+ }); });
593
+ it('fills a program path holding $& literally', function () { return __awaiter(void 0, void 0, void 0, function () {
594
+ var worker, response, body;
595
+ var _a;
596
+ return __generator(this, function (_b) {
597
+ switch (_b.label) {
598
+ case 0:
599
+ worker = loadWorker();
600
+ worker.runtime.load((_a = {},
601
+ _a[drivePath('services/public/$&x.sas')] = 'data work.class; run;',
602
+ _a));
603
+ return [4 /*yield*/, worker.dispatch('/SASjsApi/stp/execute?_program=' +
604
+ encodeURIComponent("".concat(appLoc, "/services/public/$&x")) +
605
+ '&_debug=131')];
606
+ case 1:
607
+ response = _b.sent();
608
+ expect(response.status).toBe(200);
609
+ return [4 /*yield*/, response.text()];
610
+ case 2:
611
+ body = _b.sent();
612
+ expect(body).toContain('services/public/$&x');
613
+ expect(body).not.toContain('{{program}}');
614
+ return [2 /*return*/];
615
+ }
616
+ });
617
+ }); });
618
+ it('prefers the recording that names the program over the mocked session', function () { return __awaiter(void 0, void 0, void 0, function () {
619
+ var worker, response, body;
620
+ var _a, _b;
621
+ return __generator(this, function (_c) {
622
+ switch (_c.label) {
623
+ case 0:
624
+ // The project's own output beats ours, which is why it recorded it.
625
+ ;
626
+ global.__sasTranscript = (_a = {},
627
+ _a["".concat(appLoc, "/services/public/report.sas")] = {
628
+ webout: '',
629
+ log: 'NOTE: the recorded session',
630
+ print: ''
631
+ },
632
+ _a);
633
+ worker = loadWorker();
634
+ worker.runtime.load((_b = {},
635
+ _b[drivePath('services/public/report.sas')] = 'data work.class; run;',
636
+ _b));
637
+ return [4 /*yield*/, worker.dispatch('/SASjsApi/stp/execute?_program=' +
638
+ encodeURIComponent("".concat(appLoc, "/services/public/report")) +
639
+ '&_debug=131')];
640
+ case 1:
641
+ response = _c.sent();
642
+ return [4 /*yield*/, response.text()];
643
+ case 2:
644
+ body = _c.sent();
645
+ expect(body).toContain('the recorded session');
646
+ expect(body).not.toContain('This is a mocked SAS session');
647
+ delete global.__sasTranscript;
648
+ return [2 /*return*/];
649
+ }
650
+ });
651
+ }); });
652
+ it('runs a JavaScript code run rather than answering it with the recorded session', function () { return __awaiter(void 0, void 0, void 0, function () {
653
+ var dispatch, response, body;
654
+ return __generator(this, function (_a) {
655
+ switch (_a.label) {
656
+ case 0:
657
+ // The demo's app services are JavaScript. They execute here, so a project that ships a
658
+ // fallback must not have its own code replaced by a recorded SAS session: the run time,
659
+ // not the presence of code, is what makes a run SAS.
660
+ ;
661
+ global.__sasTranscript = {
662
+ '*': {
663
+ webout: 'RECORDED-SESSION',
664
+ log: 'NOTE: the demo session',
665
+ print: ''
666
+ }
667
+ };
668
+ dispatch = seeded().dispatch;
669
+ return [4 /*yield*/, dispatch('/SASjsApi/code/execute', runRequest({ code: '_webout = "inline";', runTime: 'js', params: {} }))];
670
+ case 1:
671
+ response = _a.sent();
672
+ expect(response.status).toBe(200);
673
+ return [4 /*yield*/, response.text()];
674
+ case 2:
675
+ body = _a.sent();
676
+ expect(body.split(LOGS_SEPARATOR)[0].trim()).toBe('inline');
677
+ expect(body).not.toContain('RECORDED-SESSION');
678
+ delete global.__sasTranscript;
679
+ return [2 /*return*/];
680
+ }
681
+ });
682
+ }); });
683
+ it('runs the run time first in RUN_TIMES when a program names no extension', function () { return __awaiter(void 0, void 0, void 0, function () {
684
+ var worker, response, body;
685
+ var _a;
686
+ return __generator(this, function (_b) {
687
+ switch (_b.label) {
688
+ case 0:
689
+ // SASjs Server gives priority to the run time that comes first in `RUN_TIMES`
690
+ // (docs/pages/settings.md): with `js,sas`, `/services/public/twin` is `twin.js`. This host
691
+ // declares that order, so a project shipping both files runs the JavaScript one - and the
692
+ // SAS recording, which answers only a run time this host cannot execute, is not consulted.
693
+ ;
694
+ global.__sasTranscript = {
695
+ '*': {
696
+ webout: 'RECORDED-SESSION',
697
+ log: 'NOTE: the demo session',
698
+ print: ''
699
+ }
700
+ };
701
+ worker = seeded();
702
+ worker.runtime.load((_a = {},
703
+ _a[drivePath('services/public/twin.js')] = '_webout = "from the js twin";',
704
+ _a[drivePath('services/public/twin.sas')] = 'data work.class; run;',
705
+ _a));
706
+ return [4 /*yield*/, worker.dispatch('/SASjsApi/stp/execute?_program=' +
707
+ encodeURIComponent("".concat(appLoc, "/services/public/twin")) +
708
+ '&_debug=131')];
709
+ case 1:
710
+ response = _b.sent();
711
+ expect(response.status).toBe(200);
712
+ return [4 /*yield*/, response.text()];
713
+ case 2:
714
+ body = _b.sent();
715
+ expect(body).toContain('from the js twin');
716
+ expect(body).not.toContain('RECORDED-SESSION');
717
+ delete global.__sasTranscript;
718
+ return [2 /*return*/];
719
+ }
720
+ });
721
+ }); });
722
+ it('runs a JavaScript program rather than answering it with the recorded session', function () { return __awaiter(void 0, void 0, void 0, function () {
723
+ var worker, response, body;
724
+ var _a;
725
+ return __generator(this, function (_b) {
726
+ switch (_b.label) {
727
+ case 0:
728
+ // Same rule on the program path: a program run states no run time, so its extension
729
+ // decides - `service.js` is executed, `report.sas` is not.
730
+ ;
731
+ global.__sasTranscript = {
732
+ '*': {
733
+ webout: 'RECORDED-SESSION',
734
+ log: 'NOTE: the demo session',
735
+ print: ''
736
+ }
737
+ };
738
+ worker = seeded();
739
+ worker.runtime.load((_a = {},
740
+ _a[drivePath('services/public/service.js')] = '_webout = "from the service";',
741
+ _a));
742
+ return [4 /*yield*/, worker.dispatch('/SASjsApi/stp/execute?_program=' +
743
+ encodeURIComponent("".concat(appLoc, "/services/public/service")) +
744
+ '&_debug=131')];
745
+ case 1:
746
+ response = _b.sent();
747
+ expect(response.status).toBe(200);
518
748
  return [4 /*yield*/, response.text()];
519
749
  case 2:
520
- _a.apply(void 0, [_d.sent()]).toContain('SAS is not available');
750
+ body = _b.sent();
751
+ expect(body).toContain('from the service');
752
+ expect(body).not.toContain('RECORDED-SESSION');
521
753
  delete global.__sasTranscript;
522
754
  return [2 /*return*/];
523
755
  }
524
756
  });
525
757
  }); });
526
- it('refuses SAS code that names no recorded program', function () { return __awaiter(void 0, void 0, void 0, function () {
758
+ it('answers SAS code that names no recorded program with the mocked session', function () { return __awaiter(void 0, void 0, void 0, function () {
527
759
  var worker, _a, _b, code, response, body, e_1_1;
528
760
  var e_1, _c;
529
761
  return __generator(this, function (_d) {
@@ -544,11 +776,11 @@ describe('service worker host', function () {
544
776
  return [4 /*yield*/, worker.dispatch('/SASjsApi/code/execute', runRequest({ code: code, runTime: 'sas' }))];
545
777
  case 3:
546
778
  response = _d.sent();
547
- expect(response.status).toBe(400);
779
+ expect(response.status).toBe(200);
548
780
  return [4 /*yield*/, response.text()];
549
781
  case 4:
550
782
  body = _d.sent();
551
- expect(body).toContain('SAS is not available');
783
+ expect(body).toContain('This is a mocked SAS session');
552
784
  expect(body).not.toContain('SyntaxError');
553
785
  _d.label = 5;
554
786
  case 5:
@@ -569,7 +801,7 @@ describe('service worker host', function () {
569
801
  }
570
802
  });
571
803
  }); });
572
- it('refuses a .sas program no recording names, as it always did', function () { return __awaiter(void 0, void 0, void 0, function () {
804
+ it('answers a .sas program no recording names with the mocked session', function () { return __awaiter(void 0, void 0, void 0, function () {
573
805
  var worker, response, body;
574
806
  var _a;
575
807
  return __generator(this, function (_b) {
@@ -580,15 +812,16 @@ describe('service worker host', function () {
580
812
  _a[drivePath('services/public/other.sas')] = 'data work.class; run;',
581
813
  _a));
582
814
  return [4 /*yield*/, worker.dispatch('/SASjsApi/stp/execute?_program=' +
583
- encodeURIComponent("".concat(appLoc, "/services/public/other")))];
815
+ encodeURIComponent("".concat(appLoc, "/services/public/other")) +
816
+ '&_debug=131')];
584
817
  case 1:
585
818
  response = _b.sent();
586
- expect(response.status).toBe(400);
819
+ expect(response.status).toBe(200);
587
820
  return [4 /*yield*/, response.text()];
588
821
  case 2:
589
822
  body = _b.sent();
590
- expect(body).toContain('SAS is not available');
591
- expect(body).toContain('recorded session');
823
+ expect(body).toContain('This is a mocked SAS session');
824
+ expect(body).not.toContain('SAS is not available');
592
825
  expect(body).not.toContain('SyntaxError');
593
826
  return [2 /*return*/];
594
827
  }
@@ -1396,41 +1629,88 @@ describe('service worker host', function () {
1396
1629
  }
1397
1630
  });
1398
1631
  }); });
1399
- it('keeps a trigger a JSON answer, not the recorded transcript', function () { return __awaiter(void 0, void 0, void 0, function () {
1400
- var worker, response, body;
1401
- var _a, _b;
1402
- return __generator(this, function (_c) {
1403
- switch (_c.label) {
1632
+ it('answers a trigger of a SAS program with a session, not a refusal', function () { return __awaiter(void 0, void 0, void 0, function () {
1633
+ var worker, response, body, state, _a, output, _b;
1634
+ var _c, _d;
1635
+ return __generator(this, function (_e) {
1636
+ switch (_e.label) {
1404
1637
  case 0:
1405
- // A recording answers a run, not a trigger: the trigger route answers with
1406
- // the session record a client parses as JSON, so returning the framed
1407
- // webout there would break triggerProgram and the Studio.
1638
+ // A trigger reaches the runtime rather than the run route, so it is answered there - and
1639
+ // still as the session record a client parses as JSON, never the framed run. Returning the
1640
+ // framed webout would break triggerProgram and the Studio.
1408
1641
  ;
1409
- global.__sasTranscript = (_a = {},
1410
- _a["".concat(appLoc, "/services/public/report.sas")] = {
1642
+ global.__sasTranscript = (_c = {},
1643
+ _c["".concat(appLoc, "/services/public/report.sas")] = {
1411
1644
  webout: '{"SYSSITE":"00000000"}',
1412
1645
  log: 'NOTE: recorded',
1413
1646
  print: 'The SAS System'
1414
1647
  },
1415
- _a);
1648
+ _c);
1416
1649
  worker = loadWorker();
1417
- worker.runtime.load((_b = {},
1418
- _b[drivePath('services/public/report.sas')] = 'data work.class; run;',
1419
- _b));
1650
+ worker.runtime.load((_d = {},
1651
+ _d[drivePath('services/public/report.sas')] = 'data work.class; run;',
1652
+ _d));
1420
1653
  return [4 /*yield*/, worker.dispatch('/SASjsApi/stp/trigger?_program=' +
1421
1654
  encodeURIComponent("".concat(appLoc, "/services/public/report")), runRequest({ params: {} }))];
1422
1655
  case 1:
1423
- response = _c.sent();
1656
+ response = _e.sent();
1657
+ expect(response.status).toBe(200);
1424
1658
  expect(response.headers.get('content-type')).toContain('application/json');
1425
1659
  return [4 /*yield*/, response.json()];
1426
1660
  case 2:
1427
- body = _c.sent();
1661
+ body = _e.sent();
1428
1662
  expect(body).not.toHaveProperty('webout');
1663
+ expect(body.sessionId).toBeTruthy();
1664
+ return [4 /*yield*/, worker.dispatch("/SASjsApi/session/".concat(body.sessionId, "/state"))];
1665
+ case 3:
1666
+ state = _e.sent();
1667
+ _a = expect;
1668
+ return [4 /*yield*/, state.json()];
1669
+ case 4:
1670
+ _a.apply(void 0, [_e.sent()]).toEqual({ state: 'completed' });
1671
+ return [4 /*yield*/, worker.dispatch("/SASjsApi/session/".concat(body.sessionId, "/output"))];
1672
+ case 5:
1673
+ output = _e.sent();
1674
+ _b = expect;
1675
+ return [4 /*yield*/, output.text()];
1676
+ case 6:
1677
+ _b.apply(void 0, [_e.sent()]).toContain('SYSSITE');
1429
1678
  delete global.__sasTranscript;
1430
1679
  return [2 /*return*/];
1431
1680
  }
1432
1681
  });
1433
1682
  }); });
1683
+ it('answers a triggered SAS program the project never recorded', function () { return __awaiter(void 0, void 0, void 0, function () {
1684
+ var worker, response, sessionId, output, _a;
1685
+ var _b;
1686
+ return __generator(this, function (_c) {
1687
+ switch (_c.label) {
1688
+ case 0:
1689
+ worker = loadWorker();
1690
+ worker.runtime.load((_b = {},
1691
+ _b[drivePath('services/public/other.sas')] = 'data work.class; run;',
1692
+ _b));
1693
+ return [4 /*yield*/, worker.dispatch('/SASjsApi/stp/trigger?_program=' +
1694
+ encodeURIComponent("".concat(appLoc, "/services/public/other")), runRequest({ params: {} }))];
1695
+ case 1:
1696
+ response = _c.sent();
1697
+ expect(response.status).toBe(200);
1698
+ return [4 /*yield*/, response.json()];
1699
+ case 2:
1700
+ sessionId = (_c.sent()).sessionId;
1701
+ expect(sessionId).toBeTruthy();
1702
+ return [4 /*yield*/, worker.dispatch("/SASjsApi/session/".concat(sessionId, "/output"))];
1703
+ case 3:
1704
+ output = _c.sent();
1705
+ expect(output.status).toBe(200);
1706
+ _a = expect;
1707
+ return [4 /*yield*/, output.text()];
1708
+ case 4:
1709
+ _a.apply(void 0, [_c.sent()]).toContain('SYSSITE');
1710
+ return [2 /*return*/];
1711
+ }
1712
+ });
1713
+ }); });
1434
1714
  it('refuses a deploy upload with no archive, and one that is not a zip', function () { return __awaiter(void 0, void 0, void 0, function () {
1435
1715
  var dispatch, empty, _a, form, notZip, _b;
1436
1716
  return __generator(this, function (_c) {
@@ -7,7 +7,6 @@ exports.angularAppFiles = {
7
7
  { fileName: 'package.json' },
8
8
  { fileName: 'package-lock.json' },
9
9
  { fileName: 'tsconfig.json' },
10
- { fileName: 'tslint.json' },
11
10
  { fileName: 'angular.json' },
12
11
  { fileName: 'tsconfig.app.json' },
13
12
  { fileName: 'README.md' }
@@ -50,7 +49,6 @@ exports.angularAppFiles = {
50
49
  files: [
51
50
  { fileName: 'app.component.html' },
52
51
  { fileName: 'app.component.scss' },
53
- { fileName: 'app.component.spec.ts' },
54
52
  { fileName: 'app.component.ts' },
55
53
  { fileName: 'app.module.ts' },
56
54
  { fileName: 'app-routing.module.ts' },
@@ -64,7 +62,6 @@ exports.angularAppFiles = {
64
62
  folderName: 'sasjs-ui',
65
63
  files: [
66
64
  { fileName: 'sasjs-ui.component.html' },
67
- { fileName: 'sasjs-ui.component.spec.ts' },
68
65
  { fileName: 'sasjs-ui.component.scss' },
69
66
  { fileName: 'sasjs-ui.component.ts' }
70
67
  ],
@@ -75,7 +72,6 @@ exports.angularAppFiles = {
75
72
  files: [
76
73
  { fileName: 'data.component.html' },
77
74
  { fileName: 'data.component.scss' },
78
- { fileName: 'data.component.spec.ts' },
79
75
  { fileName: 'data.component.ts' }
80
76
  ],
81
77
  subFolders: []
@@ -85,7 +81,6 @@ exports.angularAppFiles = {
85
81
  files: [
86
82
  { fileName: 'home-page.component.html' },
87
83
  { fileName: 'home-page.component.scss' },
88
- { fileName: 'home-page.component.spec.ts' },
89
84
  { fileName: 'home-page.component.ts' }
90
85
  ],
91
86
  subFolders: []
@@ -111,8 +106,11 @@ exports.angularAppFiles = {
111
106
  ]
112
107
  },
113
108
  {
109
+ // The docs folder is a submodule, and its pages are the submodule's own
110
+ // (a docsify site today, an index.html before that). The folder is what
111
+ // this asserts; naming a page here breaks on the submodule's next change.
114
112
  folderName: 'docs',
115
- files: [{ fileName: 'index.html' }],
113
+ files: [],
116
114
  subFolders: []
117
115
  }
118
116
  ]
@@ -115,7 +115,7 @@ describe('sasjs cbd with server type SASJS', function () {
115
115
  });
116
116
  }); });
117
117
  it("should deploy compile and build to sasjs/server", function () { return __awaiter(void 0, void 0, void 0, function () {
118
- var deployMock, _a, customTarget, macroCorePath, mf_getuser, _b, mp_jsonout, ms_webout, webout, mocksPath, appinitJSPath, getdataJSPath, appinitJSContents, getdataJSContents, depsInserts, appinit, getdata, getCode;
118
+ var deployMock, _a, customTarget, macroCorePath, mf_getuser, _b, mp_jsonout, ms_webout, webout, mocksPath, appinitJSPath, getdataJSPath, springsJSONPath, appinitJSContents, getdataJSContents, springsJSONContents, depsInserts, appinit, getdata, getCode;
119
119
  return __generator(this, function (_c) {
120
120
  switch (_c.label) {
121
121
  case 0:
@@ -183,12 +183,16 @@ describe('sasjs cbd with server type SASJS', function () {
183
183
  mocksPath = path_1.default.join(__dirname, appName, 'sasjs', 'mocks');
184
184
  appinitJSPath = path_1.default.join(mocksPath, 'services', 'common', 'appinit.js');
185
185
  getdataJSPath = path_1.default.join(mocksPath, 'services', 'common', 'getdata.js');
186
+ springsJSONPath = path_1.default.join(mocksPath, 'services', 'common', 'springs.json');
186
187
  return [4 /*yield*/, (0, utils_1.readFile)(appinitJSPath)];
187
188
  case 11:
188
189
  appinitJSContents = _c.sent();
189
190
  return [4 /*yield*/, (0, utils_1.readFile)(getdataJSPath)];
190
191
  case 12:
191
192
  getdataJSContents = _c.sent();
193
+ return [4 /*yield*/, (0, utils_1.readFile)(springsJSONPath)];
194
+ case 13:
195
+ springsJSONContents = _c.sent();
192
196
  depsInserts = "\n\n* Service Variables start;\n\n\n* Service Variables end;\n* SAS Macros start;\n\n\n\n* SAS Macros end;\n* SAS Includes start;\n\n* SAS Includes end;\n* Binary Files start;\n\n* Binary Files end;\n\n\n* Service start;\n";
193
197
  appinit = "/**\n @file appinit.sas\n @brief Initialisation service - runs on app startup\n @details This is always the first service called when the app is opened.\n\n <h4> SAS Macros </h4>\n\n**/\n\nproc sql;\ncreate table areas as select distinct area\n from mydb.springs;\n\n%webout(OPEN)\n%webout(OBJ,areas)\n%webout(CLOSE)\n\n";
194
198
  getdata = "/**\n @file getdata.sas\n @brief Get Data service - runs on app startup\n @details This is always the first service called when the app is opened.\n\n <h4> SAS Macros </h4>\n\n**/\n\n%webout(FETCH)\n\nproc sql;\ncreate table springs as select * from mydb.springs\n where area in (select area from work.areas);\n\n%webout(OPEN)\n%webout(OBJ,springs)\n%webout(CLOSE)\n\n";
@@ -228,6 +232,12 @@ describe('sasjs cbd with server type SASJS', function () {
228
232
  name: 'getdata',
229
233
  type: 'service',
230
234
  code: getCode((0, utils_1.removeHeader)(getdata))
235
+ },
236
+ {
237
+ name: 'springs.json',
238
+ type: 'file',
239
+ encoding: 'base64',
240
+ code: (0, js_base64_1.encode)(springsJSONContents)
231
241
  }
232
242
  ]
233
243
  }
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
14
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
15
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -43,18 +54,29 @@ exports.createLintConfigFile = void 0;
43
54
  var path_1 = __importDefault(require("path"));
44
55
  var lint_1 = require("@sasjs/lint");
45
56
  var utils_1 = require("@sasjs/utils");
57
+ /**
58
+ * Where the settings of a `.sasjslint` are documented.
59
+ *
60
+ * The file is read as strict JSON, so it cannot carry comments - the same
61
+ * problem `sasjsconfig.json` answers with `$schema`, and the same address
62
+ * pattern (`sasjs init` writes https://cli.sasjs.io/sasjsconfig-schema.json).
63
+ * An editor that understands JSON schemas then completes the settings and
64
+ * shows each one's description as it is typed.
65
+ */
66
+ var lintSchemaUrl = 'https://cli.sasjs.io/sasjslint-schema.json';
46
67
  /**
47
68
  * Creates a SASjs Lint configuration file.
48
69
  * Its name will be of the form '.sasjslint'
49
70
  * @param {string} parentFolderName- the name of the project folder.
50
71
  */
51
72
  var createLintConfigFile = function (parentFolderName) { return __awaiter(void 0, void 0, void 0, function () {
52
- var configDestinationPath;
73
+ var configDestinationPath, config;
53
74
  return __generator(this, function (_a) {
54
75
  switch (_a.label) {
55
76
  case 0:
56
77
  configDestinationPath = path_1.default.join(process.projectDir, parentFolderName, '.sasjslint');
57
- return [4 /*yield*/, (0, utils_1.createFile)(configDestinationPath, JSON.stringify(lint_1.DefaultLintConfiguration, null, 2))];
78
+ config = __assign({ $schema: lintSchemaUrl }, lint_1.DefaultLintConfiguration);
79
+ return [4 /*yield*/, (0, utils_1.createFile)(configDestinationPath, JSON.stringify(config, null, 2))];
58
80
  case 1:
59
81
  _a.sent();
60
82
  return [2 /*return*/];