use create react app to simplify the application
This commit is contained in:
29
.gitignore
vendored
29
.gitignore
vendored
@@ -1,9 +1,24 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
.idea
|
.idea
|
||||||
.DS_Store
|
.DS_Store
|
||||||
dist
|
.env.local
|
||||||
node_modules
|
.env.development.local
|
||||||
npm-debug.log
|
.env.test.local
|
||||||
yarn-error.log
|
.env.production.local
|
||||||
aoe_technology_radar.iml
|
|
||||||
build
|
npm-debug.log*
|
||||||
# bin
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|||||||
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
_
|
||||||
4
.husky/pre-commit
Normal file
4
.husky/pre-commit
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
yarn ts:check && yarn lint-staged
|
||||||
5
.lintstagedrc
Normal file
5
.lintstagedrc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"*.{json, md, yml, js, ts, tsx}": [
|
||||||
|
"prettier --write",
|
||||||
|
]
|
||||||
|
}
|
||||||
204
LICENSE
204
LICENSE
@@ -1,204 +0,0 @@
|
|||||||
The license applies to the generator code and not the articles in the "radar" folder. (Read also the README.md in this folder)
|
|
||||||
|
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright 2017 Google Inc.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
21
README.md
21
README.md
@@ -24,9 +24,14 @@ Add the tech radar as a dependency
|
|||||||
yarn add https://github.com/aoepeople/aoe_technology_radar.git
|
yarn add https://github.com/aoepeople/aoe_technology_radar.git
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Generate json file based on md files
|
||||||
|
```
|
||||||
|
yarn generateJson
|
||||||
|
```
|
||||||
|
|
||||||
Build the radar
|
Build the radar
|
||||||
```
|
```
|
||||||
yarn aoe_technology_radar
|
yarn buildRadar
|
||||||
```
|
```
|
||||||
|
|
||||||
Serve
|
Serve
|
||||||
@@ -36,20 +41,6 @@ python3 -m http.server 8080
|
|||||||
```
|
```
|
||||||
Then open here: http://localhost:8080
|
Then open here: http://localhost:8080
|
||||||
|
|
||||||
## Run a prepared static version
|
|
||||||
|
|
||||||
In most cases you have the techradar available at `/techradar`, and for reasons want all correct pages to be accessable.
|
|
||||||
|
|
||||||
Until this setup improves, you can use the following way to generate the correct techradar:
|
|
||||||
|
|
||||||
```
|
|
||||||
PUBLIC_URL=techradar/ yarn aoe_technology_radar
|
|
||||||
yarn aoe_technology_radar-static
|
|
||||||
cp -r build techradar
|
|
||||||
```
|
|
||||||
|
|
||||||
(This is rather workaroundish for now, but does the job.)
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
For a new Technology Radar release, create a folder of the release date
|
For a new Technology Radar release, create a folder of the release date
|
||||||
|
|||||||
@@ -16,20 +16,22 @@ exports.rings = [
|
|||||||
'assess',
|
'assess',
|
||||||
'hold'
|
'hold'
|
||||||
];
|
];
|
||||||
exports.getItemPageNames = (items) => items.map(item => `${item.quadrant}/${item.name}`);
|
var getItemPageNames = function (items) { return items.map(function (item) { return item.quadrant + "/" + item.name; }); };
|
||||||
|
exports.getItemPageNames = getItemPageNames;
|
||||||
exports.showEmptyRings = false;
|
exports.showEmptyRings = false;
|
||||||
const messages = {
|
var messages = {
|
||||||
'languages-and-frameworks': 'Languages & Frameworks',
|
'languages-and-frameworks': 'Languages & Frameworks',
|
||||||
'methods-and-patterns': 'Methods & Patterns',
|
'methods-and-patterns': 'Methods & Patterns',
|
||||||
'platforms-and-aoe-services': 'Platforms and Operations',
|
'platforms-and-aoe-services': 'Platforms and Operations',
|
||||||
'tools': 'Tools',
|
'tools': 'Tools',
|
||||||
};
|
};
|
||||||
exports.translate = (key) => (messages[key] || '-');
|
var translate = function (key) { return (messages[key] || '-'); };
|
||||||
|
exports.translate = translate;
|
||||||
function isMobileViewport() {
|
function isMobileViewport() {
|
||||||
// return false for server side rendering
|
// return false for server side rendering
|
||||||
if (typeof window == 'undefined')
|
if (typeof window == 'undefined')
|
||||||
return false;
|
return false;
|
||||||
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
return width < 1200;
|
return width < 1200;
|
||||||
}
|
}
|
||||||
exports.isMobileViewport = isMobileViewport;
|
exports.isMobileViewport = isMobileViewport;
|
||||||
|
|||||||
@@ -1,18 +1,56 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
var __assign = (this && this.__assign) || function () {
|
||||||
|
__assign = Object.assign || function(t) {
|
||||||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
|
s = arguments[i];
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||||
|
t[p] = s[p];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
return __assign.apply(this, arguments);
|
||||||
|
};
|
||||||
|
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
||||||
|
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
|
||||||
|
to[j] = from[i];
|
||||||
|
return to;
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.getFirstLetter = exports.groupByFirstLetter = exports.groupByQuadrants = exports.featuredOnly = void 0;
|
exports.getFirstLetter = exports.groupByFirstLetter = exports.groupByQuadrants = exports.featuredOnly = void 0;
|
||||||
exports.featuredOnly = (items) => items.filter(item => item.featured);
|
var featuredOnly = function (items) { return items.filter(function (item) { return item.featured; }); };
|
||||||
exports.groupByQuadrants = (items) => items.reduce((quadrants, item) => (Object.assign(Object.assign({}, quadrants), { [item.quadrant]: addItemToQuadrant(quadrants[item.quadrant], item) })), {});
|
exports.featuredOnly = featuredOnly;
|
||||||
exports.groupByFirstLetter = (items) => {
|
var groupByQuadrants = function (items) {
|
||||||
const index = items.reduce((letterIndex, item) => (Object.assign(Object.assign({}, letterIndex), { [exports.getFirstLetter(item)]: addItemToList(letterIndex[exports.getFirstLetter(item)], item) })), {});
|
return items.reduce(function (quadrants, item) {
|
||||||
|
var _a;
|
||||||
|
return (__assign(__assign({}, quadrants), (_a = {}, _a[item.quadrant] = addItemToQuadrant(quadrants[item.quadrant], item), _a)));
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
exports.groupByQuadrants = groupByQuadrants;
|
||||||
|
var groupByFirstLetter = function (items) {
|
||||||
|
var index = items.reduce(function (letterIndex, item) {
|
||||||
|
var _a;
|
||||||
|
return (__assign(__assign({}, letterIndex), (_a = {}, _a[exports.getFirstLetter(item)] = addItemToList(letterIndex[exports.getFirstLetter(item)], item), _a)));
|
||||||
|
}, {});
|
||||||
return Object.keys(index)
|
return Object.keys(index)
|
||||||
.sort()
|
.sort()
|
||||||
.map(letter => ({
|
.map(function (letter) { return ({
|
||||||
letter,
|
letter: letter,
|
||||||
items: index[letter],
|
items: index[letter],
|
||||||
}));
|
}); });
|
||||||
};
|
};
|
||||||
const addItemToQuadrant = (quadrant = {}, item) => (Object.assign(Object.assign({}, quadrant), { [item.ring]: addItemToRing(quadrant[item.ring], item) }));
|
exports.groupByFirstLetter = groupByFirstLetter;
|
||||||
const addItemToList = (list = [], item) => [...list, item];
|
var addItemToQuadrant = function (quadrant, item) {
|
||||||
const addItemToRing = (ring = [], item) => [...ring, item];
|
var _a;
|
||||||
exports.getFirstLetter = (item) => item.title.substr(0, 1).toUpperCase();
|
if (quadrant === void 0) { quadrant = {}; }
|
||||||
|
return (__assign(__assign({}, quadrant), (_a = {}, _a[item.ring] = addItemToRing(quadrant[item.ring], item), _a)));
|
||||||
|
};
|
||||||
|
var addItemToList = function (list, item) {
|
||||||
|
if (list === void 0) { list = []; }
|
||||||
|
return __spreadArray(__spreadArray([], list), [item]);
|
||||||
|
};
|
||||||
|
var addItemToRing = function (ring, item) {
|
||||||
|
if (ring === void 0) { ring = []; }
|
||||||
|
return __spreadArray(__spreadArray([], ring), [item]);
|
||||||
|
};
|
||||||
|
var getFirstLetter = function (item) { return item.title.substr(0, 1).toUpperCase(); };
|
||||||
|
exports.getFirstLetter = getFirstLetter;
|
||||||
|
|||||||
61
bin/tasks/create-static.js
Executable file → Normal file
61
bin/tasks/create-static.js
Executable file → Normal file
@@ -9,26 +9,63 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (_) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const radar_1 = require("./radar");
|
var radar_1 = require("./radar");
|
||||||
const fs_1 = require("fs");
|
var fs_1 = require("fs");
|
||||||
const config_1 = require("../src/config");
|
var config_1 = require("../src/config");
|
||||||
(() => __awaiter(void 0, void 0, void 0, function* () {
|
(function () { return __awaiter(void 0, void 0, void 0, function () {
|
||||||
try {
|
var radar, e_1;
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0:
|
||||||
|
_a.trys.push([0, 2, , 3]);
|
||||||
console.log('starting static');
|
console.log('starting static');
|
||||||
const radar = yield radar_1.createRadar();
|
return [4 /*yield*/, radar_1.createRadar()];
|
||||||
|
case 1:
|
||||||
|
radar = _a.sent();
|
||||||
fs_1.copyFileSync('build/index.html', 'build/overview.html');
|
fs_1.copyFileSync('build/index.html', 'build/overview.html');
|
||||||
fs_1.copyFileSync('build/index.html', 'build/help-and-about-tech-radar.html');
|
fs_1.copyFileSync('build/index.html', 'build/help-and-about-tech-radar.html');
|
||||||
config_1.quadrants.forEach(quadrant => {
|
config_1.quadrants.forEach(function (quadrant) {
|
||||||
fs_1.copyFileSync('build/index.html', 'build/' + quadrant + '.html');
|
fs_1.copyFileSync('build/index.html', 'build/' + quadrant + '.html');
|
||||||
fs_1.mkdirSync('build/' + quadrant);
|
fs_1.mkdirSync('build/' + quadrant);
|
||||||
});
|
});
|
||||||
radar.items.forEach(item => {
|
radar.items.forEach(function (item) {
|
||||||
fs_1.copyFileSync('build/index.html', 'build/' + item.quadrant + '/' + item.name + '.html');
|
fs_1.copyFileSync('build/index.html', 'build/' + item.quadrant + '/' + item.name + '.html');
|
||||||
});
|
});
|
||||||
console.log('created static');
|
console.log('created static');
|
||||||
|
return [3 /*break*/, 3];
|
||||||
|
case 2:
|
||||||
|
e_1 = _a.sent();
|
||||||
|
console.error('error:', e_1);
|
||||||
|
return [3 /*break*/, 3];
|
||||||
|
case 3: return [2 /*return*/];
|
||||||
}
|
}
|
||||||
catch (e) {
|
});
|
||||||
console.error('error:', e);
|
}); })();
|
||||||
}
|
|
||||||
}))();
|
|
||||||
|
|||||||
123
bin/tasks/file.js
Executable file → Normal file
123
bin/tasks/file.js
Executable file → Normal file
@@ -1,43 +1,120 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
||||||
|
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
|
||||||
|
to[j] = from[i];
|
||||||
|
return to;
|
||||||
|
};
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.save = exports.getAllMarkdownFiles = exports.distPath = exports.jsPath = exports.faviconPath = exports.assetsPath = exports.stylesPath = exports.radarPath = exports.relativePath = void 0;
|
exports.save = exports.getAllMarkdownFiles = exports.builderPath = exports.buildPath = exports.publicPath = exports.jsPath = exports.faviconPath = exports.assetsPath = exports.stylesPath = exports.radarPath = exports.relativePath = void 0;
|
||||||
const fs_extra_1 = require("fs-extra");
|
var fs_extra_1 = require("fs-extra");
|
||||||
const path_1 = __importDefault(require("path"));
|
var path_1 = __importDefault(require("path"));
|
||||||
const walk_1 = require("walk");
|
var walk_1 = require("walk");
|
||||||
exports.relativePath = (...relativePath) => (
|
var relativePath = function () {
|
||||||
|
var relativePath = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
relativePath[_i] = arguments[_i];
|
||||||
|
}
|
||||||
// path.resolve(__dirname, '..', ...relativePath)
|
// path.resolve(__dirname, '..', ...relativePath)
|
||||||
path_1.default.resolve(...relativePath));
|
return path_1.default.resolve.apply(path_1.default, relativePath);
|
||||||
exports.radarPath = (...pathInSrc) => (exports.relativePath('radar', ...pathInSrc));
|
};
|
||||||
exports.stylesPath = (...pathInSrc) => (exports.relativePath('styles', ...pathInSrc));
|
exports.relativePath = relativePath;
|
||||||
exports.assetsPath = (...pathInSrc) => (exports.relativePath('assets', ...pathInSrc));
|
var radarPath = function () {
|
||||||
exports.faviconPath = (...pathInSrc) => (exports.relativePath('assets/favicon.ico', ...pathInSrc));
|
var pathInSrc = [];
|
||||||
exports.jsPath = (...pathInSrc) => (exports.relativePath('js', ...pathInSrc));
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
exports.distPath = (...pathInDist) => (exports.relativePath('src', ...pathInDist));
|
pathInSrc[_i] = arguments[_i];
|
||||||
exports.getAllMarkdownFiles = (folder) => (getAllFiles(folder, isMarkdownFile));
|
}
|
||||||
const getAllFiles = (folder, predicate) => (new Promise((resolve, reject) => {
|
return exports.relativePath.apply(void 0, __spreadArray(["radar"], pathInSrc));
|
||||||
const walker = walk_1.walk(folder, { followLinks: false });
|
};
|
||||||
const files = [];
|
exports.radarPath = radarPath;
|
||||||
walker.on("file", (root, fileStat, next) => {
|
var stylesPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return exports.relativePath.apply(void 0, __spreadArray(["styles"], pathInSrc));
|
||||||
|
};
|
||||||
|
exports.stylesPath = stylesPath;
|
||||||
|
var assetsPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return exports.relativePath.apply(void 0, __spreadArray(["assets"], pathInSrc));
|
||||||
|
};
|
||||||
|
exports.assetsPath = assetsPath;
|
||||||
|
var faviconPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return exports.relativePath.apply(void 0, __spreadArray(["assets/favicon.ico"], pathInSrc));
|
||||||
|
};
|
||||||
|
exports.faviconPath = faviconPath;
|
||||||
|
var jsPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return exports.relativePath.apply(void 0, __spreadArray(["js"], pathInSrc));
|
||||||
|
};
|
||||||
|
exports.jsPath = jsPath;
|
||||||
|
var publicPath = function () {
|
||||||
|
var pathInDist = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInDist[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return exports.relativePath.apply(void 0, __spreadArray(["public"], pathInDist));
|
||||||
|
};
|
||||||
|
exports.publicPath = publicPath;
|
||||||
|
var buildPath = function () {
|
||||||
|
var pathInDist = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInDist[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return exports.relativePath.apply(void 0, __spreadArray(["build"], pathInDist));
|
||||||
|
};
|
||||||
|
exports.buildPath = buildPath;
|
||||||
|
var builderPath = function () {
|
||||||
|
var pathInDist = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInDist[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return exports.relativePath.apply(void 0, __spreadArray(["node_modules", "aoe_technology_radar", "src"], pathInDist));
|
||||||
|
};
|
||||||
|
exports.builderPath = builderPath;
|
||||||
|
var getAllMarkdownFiles = function (folder) {
|
||||||
|
return getAllFiles(folder, isMarkdownFile);
|
||||||
|
};
|
||||||
|
exports.getAllMarkdownFiles = getAllMarkdownFiles;
|
||||||
|
var getAllFiles = function (folder, predicate) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var walker = walk_1.walk(folder, { followLinks: false });
|
||||||
|
var files = [];
|
||||||
|
walker.on("file", function (root, fileStat, next) {
|
||||||
if (predicate(fileStat.name)) {
|
if (predicate(fileStat.name)) {
|
||||||
files.push(path_1.default.resolve(root, fileStat.name));
|
files.push(path_1.default.resolve(root, fileStat.name));
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
walker.on("errors", (root, nodeStatsArray, next) => {
|
walker.on("errors", function (root, nodeStatsArray, next) {
|
||||||
nodeStatsArray.forEach(function (n) {
|
nodeStatsArray.forEach(function (n) {
|
||||||
console.error("[ERROR] " + n.name);
|
console.error("[ERROR] " + n.name);
|
||||||
if (n.error) {
|
if (n.error) {
|
||||||
console.error(n.error.message || (n.error.code + ": " + n.error.path));
|
console.error(n.error.message || n.error.code + ": " + n.error.path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
walker.on("end", () => {
|
walker.on("end", function () {
|
||||||
resolve(files.sort());
|
resolve(files.sort());
|
||||||
});
|
});
|
||||||
}));
|
});
|
||||||
const isMarkdownFile = (name) => name.match(/\.md$/) !== null;
|
};
|
||||||
exports.save = (data, fileName) => fs_extra_1.outputFile(exports.distPath(fileName), data);
|
var isMarkdownFile = function (name) { return name.match(/\.md$/) !== null; };
|
||||||
|
var save = function (data, fileName) {
|
||||||
|
return fs_extra_1.outputFile(exports.buildPath(fileName), data);
|
||||||
|
};
|
||||||
|
exports.save = save;
|
||||||
|
|||||||
165
bin/tasks/radar.js
Executable file → Normal file
165
bin/tasks/radar.js
Executable file → Normal file
@@ -1,4 +1,15 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
var __assign = (this && this.__assign) || function () {
|
||||||
|
__assign = Object.assign || function(t) {
|
||||||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
|
s = arguments[i];
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||||
|
t[p] = s[p];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
return __assign.apply(this, arguments);
|
||||||
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
@@ -8,86 +19,138 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (_) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
||||||
|
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
|
||||||
|
to[j] = from[i];
|
||||||
|
return to;
|
||||||
|
};
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.createRadar = void 0;
|
exports.createRadar = void 0;
|
||||||
const fs_extra_1 = require("fs-extra");
|
var fs_extra_1 = require("fs-extra");
|
||||||
const path_1 = __importDefault(require("path"));
|
var path_1 = __importDefault(require("path"));
|
||||||
const front_matter_1 = __importDefault(require("front-matter"));
|
var front_matter_1 = __importDefault(require("front-matter"));
|
||||||
const marked_1 = __importDefault(require("marked"));
|
var marked_1 = __importDefault(require("marked"));
|
||||||
const highlight_js_1 = __importDefault(require("highlight.js"));
|
var highlight_js_1 = __importDefault(require("highlight.js"));
|
||||||
const config_1 = require("../src/config");
|
var config_1 = require("../src/config");
|
||||||
const file_1 = require("./file");
|
var file_1 = require("./file");
|
||||||
marked_1.default.setOptions({
|
marked_1.default.setOptions({
|
||||||
highlight: code => highlight_js_1.default.highlightAuto(code).value,
|
highlight: function (code) { return highlight_js_1.default.highlightAuto(code).value; },
|
||||||
});
|
});
|
||||||
exports.createRadar = () => __awaiter(void 0, void 0, void 0, function* () {
|
var createRadar = function () { return __awaiter(void 0, void 0, void 0, function () {
|
||||||
const fileNames = yield file_1.getAllMarkdownFiles(file_1.radarPath());
|
var fileNames, revisions, allReleases, items, flaggedItems;
|
||||||
const revisions = yield createRevisionsFromFiles(fileNames);
|
return __generator(this, function (_a) {
|
||||||
const allReleases = getAllReleases(revisions);
|
switch (_a.label) {
|
||||||
const items = createItems(revisions);
|
case 0: return [4 /*yield*/, file_1.getAllMarkdownFiles(file_1.radarPath())];
|
||||||
const flaggedItems = flagItem(items, allReleases);
|
case 1:
|
||||||
return {
|
fileNames = _a.sent();
|
||||||
|
return [4 /*yield*/, createRevisionsFromFiles(fileNames)];
|
||||||
|
case 2:
|
||||||
|
revisions = _a.sent();
|
||||||
|
allReleases = getAllReleases(revisions);
|
||||||
|
items = createItems(revisions);
|
||||||
|
flaggedItems = flagItem(items, allReleases);
|
||||||
|
return [2 /*return*/, {
|
||||||
items: flaggedItems,
|
items: flaggedItems,
|
||||||
releases: allReleases,
|
releases: allReleases,
|
||||||
};
|
}];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const checkAttributes = (fileName, attributes) => {
|
}); };
|
||||||
|
exports.createRadar = createRadar;
|
||||||
|
var checkAttributes = function (fileName, attributes) {
|
||||||
if (attributes.ring && !config_1.rings.includes(attributes.ring)) {
|
if (attributes.ring && !config_1.rings.includes(attributes.ring)) {
|
||||||
throw new Error(`Error: ${fileName} has an illegal value for 'ring' - must be one of ${config_1.rings}`);
|
throw new Error("Error: " + fileName + " has an illegal value for 'ring' - must be one of " + config_1.rings);
|
||||||
}
|
}
|
||||||
if (attributes.quadrant && !config_1.quadrants.includes(attributes.quadrant)) {
|
if (attributes.quadrant && !config_1.quadrants.includes(attributes.quadrant)) {
|
||||||
throw new Error(`Error: ${fileName} has an illegal value for 'quadrant' - must be one of ${config_1.quadrants}`);
|
throw new Error("Error: " + fileName + " has an illegal value for 'quadrant' - must be one of " + config_1.quadrants);
|
||||||
}
|
}
|
||||||
return attributes;
|
return attributes;
|
||||||
};
|
};
|
||||||
const createRevisionsFromFiles = (fileNames) => Promise.all(fileNames.map(fileName => {
|
var createRevisionsFromFiles = function (fileNames) {
|
||||||
return new Promise((resolve, reject) => {
|
return Promise.all(fileNames.map(function (fileName) {
|
||||||
fs_extra_1.readFile(fileName, 'utf8', (err, data) => {
|
return new Promise(function (resolve, reject) {
|
||||||
|
fs_extra_1.readFile(fileName, 'utf8', function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const fm = front_matter_1.default(data);
|
var fm = front_matter_1.default(data);
|
||||||
// add target attribute to external links
|
// add target attribute to external links
|
||||||
// todo: check path
|
// todo: check path
|
||||||
let html = marked_1.default(fm.body.replace(/\]\(\//g, '](/techradar/'));
|
var html = marked_1.default(fm.body.replace(/\]\(\//g, '](/techradar/'));
|
||||||
html = html.replace(/a href="http/g, 'a target="_blank" rel="noopener noreferrer" href="http');
|
html = html.replace(/a href="http/g, 'a target="_blank" rel="noopener noreferrer" href="http');
|
||||||
resolve(Object.assign(Object.assign(Object.assign({}, itemInfoFromFilename(fileName)), checkAttributes(fileName, fm.attributes)), { fileName, body: html }));
|
resolve(__assign(__assign(__assign({}, itemInfoFromFilename(fileName)), checkAttributes(fileName, fm.attributes)), { fileName: fileName, body: html }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
const itemInfoFromFilename = (fileName) => {
|
};
|
||||||
const [release, name] = fileName.split(path_1.default.sep).slice(-2);
|
var itemInfoFromFilename = function (fileName) {
|
||||||
|
var _a = fileName.split(path_1.default.sep).slice(-2), release = _a[0], name = _a[1];
|
||||||
return {
|
return {
|
||||||
name: path_1.default.basename(name, '.md'),
|
name: path_1.default.basename(name, '.md'),
|
||||||
release,
|
release: release,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const getAllReleases = (revisions) => revisions
|
var getAllReleases = function (revisions) {
|
||||||
.reduce((allReleases, { release }) => {
|
return revisions
|
||||||
|
.reduce(function (allReleases, _a) {
|
||||||
|
var release = _a.release;
|
||||||
if (!allReleases.includes(release)) {
|
if (!allReleases.includes(release)) {
|
||||||
return [...allReleases, release];
|
return __spreadArray(__spreadArray([], allReleases), [release]);
|
||||||
}
|
}
|
||||||
return allReleases;
|
return allReleases;
|
||||||
}, [])
|
}, [])
|
||||||
.sort();
|
.sort();
|
||||||
const createItems = (revisions) => {
|
|
||||||
const itemMap = revisions.reduce((items, revision) => {
|
|
||||||
return Object.assign(Object.assign({}, items), { [revision.name]: addRevisionToItem(items[revision.name], revision) });
|
|
||||||
}, {});
|
|
||||||
return Object.values(itemMap).map(item => (Object.assign(Object.assign({}, item), { ['title']: item.title || item.name }))).sort((x, y) => (x.name > y.name ? 1 : -1));
|
|
||||||
};
|
};
|
||||||
const ignoreEmptyRevisionBody = (revision, item) => {
|
var createItems = function (revisions) {
|
||||||
|
var itemMap = revisions.reduce(function (items, revision) {
|
||||||
|
var _a;
|
||||||
|
return __assign(__assign({}, items), (_a = {}, _a[revision.name] = addRevisionToItem(items[revision.name], revision), _a));
|
||||||
|
}, {});
|
||||||
|
return Object.values(itemMap).map(function (item) {
|
||||||
|
var _a;
|
||||||
|
return (__assign(__assign({}, item), (_a = {}, _a['title'] = item.title || item.name, _a)));
|
||||||
|
}).sort(function (x, y) { return (x.name > y.name ? 1 : -1); });
|
||||||
|
};
|
||||||
|
var ignoreEmptyRevisionBody = function (revision, item) {
|
||||||
if (!revision.body || revision.body.trim() === '') {
|
if (!revision.body || revision.body.trim() === '') {
|
||||||
return item.body;
|
return item.body;
|
||||||
}
|
}
|
||||||
return revision.body;
|
return revision.body;
|
||||||
};
|
};
|
||||||
const addRevisionToItem = (item = {
|
var addRevisionToItem = function (item, revision) {
|
||||||
|
if (item === void 0) { item = {
|
||||||
flag: 'default',
|
flag: 'default',
|
||||||
featured: true,
|
featured: true,
|
||||||
revisions: [],
|
revisions: [],
|
||||||
@@ -97,21 +160,29 @@ const addRevisionToItem = (item = {
|
|||||||
quadrant: '',
|
quadrant: '',
|
||||||
body: '',
|
body: '',
|
||||||
info: '',
|
info: '',
|
||||||
}, revision) => {
|
}; }
|
||||||
let newItem = Object.assign(Object.assign(Object.assign({}, item), revision), { body: ignoreEmptyRevisionBody(revision, item) });
|
var newItem = __assign(__assign(__assign({}, item), revision), { body: ignoreEmptyRevisionBody(revision, item) });
|
||||||
if (revisionCreatesNewHistoryEntry(revision)) {
|
if (revisionCreatesNewHistoryEntry(revision)) {
|
||||||
newItem = Object.assign(Object.assign({}, newItem), { revisions: [revision, ...newItem.revisions] });
|
newItem = __assign(__assign({}, newItem), { revisions: __spreadArray([revision], newItem.revisions) });
|
||||||
}
|
}
|
||||||
return newItem;
|
return newItem;
|
||||||
};
|
};
|
||||||
const revisionCreatesNewHistoryEntry = (revision) => {
|
var revisionCreatesNewHistoryEntry = function (revision) {
|
||||||
return revision.body.trim() !== '' || typeof revision.ring !== 'undefined';
|
return revision.body.trim() !== '' || typeof revision.ring !== 'undefined';
|
||||||
};
|
};
|
||||||
const flagItem = (items, allReleases) => items.map(item => (Object.assign(Object.assign({}, item), { flag: getItemFlag(item, allReleases) })), []);
|
var flagItem = function (items, allReleases) {
|
||||||
const isInLastRelease = (item, allReleases) => item.revisions[0].release === allReleases[allReleases.length - 1];
|
return items.map(function (item) { return (__assign(__assign({}, item), { flag: getItemFlag(item, allReleases) })); }, []);
|
||||||
const isNewItem = (item, allReleases) => item.revisions.length === 1 && isInLastRelease(item, allReleases);
|
};
|
||||||
const hasItemChanged = (item, allReleases) => item.revisions.length > 1 && isInLastRelease(item, allReleases);
|
var isInLastRelease = function (item, allReleases) {
|
||||||
const getItemFlag = (item, allReleases) => {
|
return item.revisions[0].release === allReleases[allReleases.length - 1];
|
||||||
|
};
|
||||||
|
var isNewItem = function (item, allReleases) {
|
||||||
|
return item.revisions.length === 1 && isInLastRelease(item, allReleases);
|
||||||
|
};
|
||||||
|
var hasItemChanged = function (item, allReleases) {
|
||||||
|
return item.revisions.length > 1 && isInLastRelease(item, allReleases);
|
||||||
|
};
|
||||||
|
var getItemFlag = function (item, allReleases) {
|
||||||
if (isNewItem(item, allReleases)) {
|
if (isNewItem(item, allReleases)) {
|
||||||
return 'new';
|
return 'new';
|
||||||
}
|
}
|
||||||
|
|||||||
77
bin/tasks/radarjson.js
Executable file → Normal file
77
bin/tasks/radarjson.js
Executable file → Normal file
@@ -9,33 +9,56 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (_) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.radarJsonGenerator = void 0;
|
exports.radarJsonGenerator = void 0;
|
||||||
const radar_1 = require("./radar");
|
var radar_1 = require("./radar");
|
||||||
const file_1 = require("./file");
|
var file_1 = require("./file");
|
||||||
exports.radarJsonGenerator = (() => __awaiter(void 0, void 0, void 0, function* () {
|
var radarJsonGenerator = function () { return __awaiter(void 0, void 0, void 0, function () {
|
||||||
try {
|
var radar, e_1;
|
||||||
console.log('start');
|
return __generator(this, function (_a) {
|
||||||
const radar = yield radar_1.createRadar();
|
switch (_a.label) {
|
||||||
// console.log(radar);
|
case 0:
|
||||||
file_1.save(JSON.stringify(radar), 'rd.json');
|
_a.trys.push([0, 3, , 4]);
|
||||||
file_1.save(`import React from 'react';
|
return [4 /*yield*/, radar_1.createRadar()];
|
||||||
import ReactDOM from 'react-dom';
|
case 1:
|
||||||
import App from 'aoe_technology_radar/src/components/App';
|
radar = _a.sent();
|
||||||
import 'aoe_technology_radar/src/index.scss';
|
return [4 /*yield*/, file_1.save(JSON.stringify(radar), "rd.json")];
|
||||||
import {Item} from "aoe_technology_radar/src/model";
|
case 2:
|
||||||
import radardata from './rd.json';
|
_a.sent();
|
||||||
|
return [3 /*break*/, 4];
|
||||||
ReactDOM.render(
|
case 3:
|
||||||
<React.StrictMode>
|
e_1 = _a.sent();
|
||||||
<App items={radardata.items as Item[]} releases={radardata.releases as string[]} />
|
console.error("error:", e_1);
|
||||||
</React.StrictMode>,
|
return [3 /*break*/, 4];
|
||||||
document.getElementById('root')
|
case 4: return [2 /*return*/];
|
||||||
);
|
|
||||||
`, 'index.tsx');
|
|
||||||
console.log('Built radar');
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
});
|
||||||
console.error('error:', e);
|
}); };
|
||||||
}
|
exports.radarJsonGenerator = radarJsonGenerator;
|
||||||
}));
|
|
||||||
|
|||||||
104
config/env.js
104
config/env.js
@@ -1,104 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const paths = require('./paths');
|
|
||||||
|
|
||||||
// Make sure that including paths.js after env.js will read .env variables.
|
|
||||||
delete require.cache[require.resolve('./paths')];
|
|
||||||
|
|
||||||
const NODE_ENV = process.env.NODE_ENV;
|
|
||||||
if (!NODE_ENV) {
|
|
||||||
throw new Error(
|
|
||||||
'The NODE_ENV environment variable is required but was not specified.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
|
|
||||||
const dotenvFiles = [
|
|
||||||
`${paths.dotenv}.${NODE_ENV}.local`,
|
|
||||||
`${paths.dotenv}.${NODE_ENV}`,
|
|
||||||
// Don't include `.env.local` for `test` environment
|
|
||||||
// since normally you expect tests to produce the same
|
|
||||||
// results for everyone
|
|
||||||
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
|
|
||||||
paths.dotenv,
|
|
||||||
].filter(Boolean);
|
|
||||||
|
|
||||||
// Load environment variables from .env* files. Suppress warnings using silent
|
|
||||||
// if this file is missing. dotenv will never modify any environment variables
|
|
||||||
// that have already been set. Variable expansion is supported in .env files.
|
|
||||||
// https://github.com/motdotla/dotenv
|
|
||||||
// https://github.com/motdotla/dotenv-expand
|
|
||||||
dotenvFiles.forEach(dotenvFile => {
|
|
||||||
if (fs.existsSync(dotenvFile)) {
|
|
||||||
require('dotenv-expand')(
|
|
||||||
require('dotenv').config({
|
|
||||||
path: dotenvFile,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// We support resolving modules according to `NODE_PATH`.
|
|
||||||
// This lets you use absolute paths in imports inside large monorepos:
|
|
||||||
// https://github.com/facebook/create-react-app/issues/253.
|
|
||||||
// It works similar to `NODE_PATH` in Node itself:
|
|
||||||
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
|
|
||||||
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
|
|
||||||
// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
|
|
||||||
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
|
|
||||||
// We also resolve them to make sure all tools using them work consistently.
|
|
||||||
const appDirectory = fs.realpathSync(process.cwd());
|
|
||||||
process.env.NODE_PATH = (process.env.NODE_PATH || '')
|
|
||||||
.split(path.delimiter)
|
|
||||||
.filter(folder => folder && !path.isAbsolute(folder))
|
|
||||||
.map(folder => path.resolve(appDirectory, folder))
|
|
||||||
.join(path.delimiter);
|
|
||||||
|
|
||||||
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
|
|
||||||
// injected into the application via DefinePlugin in webpack configuration.
|
|
||||||
const REACT_APP = /^REACT_APP_/i;
|
|
||||||
|
|
||||||
function getClientEnvironment(publicUrl) {
|
|
||||||
const raw = Object.keys(process.env)
|
|
||||||
.filter(key => REACT_APP.test(key))
|
|
||||||
.reduce(
|
|
||||||
(env, key) => {
|
|
||||||
env[key] = process.env[key];
|
|
||||||
return env;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Useful for determining whether we’re running in production mode.
|
|
||||||
// Most importantly, it switches React into the correct mode.
|
|
||||||
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
||||||
// Useful for resolving the correct path to static assets in `public`.
|
|
||||||
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
|
|
||||||
// This should only be used as an escape hatch. Normally you would put
|
|
||||||
// images into the `src` and `import` them in code to get their paths.
|
|
||||||
PUBLIC_URL: publicUrl,
|
|
||||||
|
|
||||||
RADAR_NAME: process.env.RADAR_NAME || 'AOE Technology Radar',
|
|
||||||
|
|
||||||
// We support configuring the sockjs pathname during development.
|
|
||||||
// These settings let a developer run multiple simultaneous projects.
|
|
||||||
// They are used as the connection `hostname`, `pathname` and `port`
|
|
||||||
// in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
|
|
||||||
// and `sockPort` options in webpack-dev-server.
|
|
||||||
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
|
||||||
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
|
||||||
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// Stringify all values so we can feed into webpack DefinePlugin
|
|
||||||
const stringified = {
|
|
||||||
'process.env': Object.keys(raw).reduce((env, key) => {
|
|
||||||
env[key] = JSON.stringify(raw[key]);
|
|
||||||
return env;
|
|
||||||
}, {}),
|
|
||||||
};
|
|
||||||
|
|
||||||
return { raw, stringified };
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = getClientEnvironment;
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const chalk = require('react-dev-utils/chalk');
|
|
||||||
const paths = require('./paths');
|
|
||||||
|
|
||||||
// Ensure the certificate and key provided are valid and if not
|
|
||||||
// throw an easy to debug error
|
|
||||||
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
|
|
||||||
let encrypted;
|
|
||||||
try {
|
|
||||||
// publicEncrypt will throw an error with an invalid cert
|
|
||||||
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(
|
|
||||||
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// privateDecrypt will throw an error with an invalid key
|
|
||||||
crypto.privateDecrypt(key, encrypted);
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(
|
|
||||||
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
|
|
||||||
err.message
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read file and throw an error if it doesn't exist
|
|
||||||
function readEnvFile(file, type) {
|
|
||||||
if (!fs.existsSync(file)) {
|
|
||||||
throw new Error(
|
|
||||||
`You specified ${chalk.cyan(
|
|
||||||
type
|
|
||||||
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return fs.readFileSync(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the https config
|
|
||||||
// Return cert files if provided in env, otherwise just true or false
|
|
||||||
function getHttpsConfig() {
|
|
||||||
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
|
|
||||||
const isHttps = HTTPS === 'true';
|
|
||||||
|
|
||||||
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
|
|
||||||
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
|
|
||||||
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
|
|
||||||
const config = {
|
|
||||||
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
|
|
||||||
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
|
|
||||||
};
|
|
||||||
|
|
||||||
validateKeyAndCerts({ ...config, keyFile, crtFile });
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
return isHttps;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = getHttpsConfig;
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
// This is a custom Jest transformer turning style imports into empty objects.
|
|
||||||
// http://facebook.github.io/jest/docs/en/webpack.html
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
process() {
|
|
||||||
return 'module.exports = {};';
|
|
||||||
},
|
|
||||||
getCacheKey() {
|
|
||||||
// The output is always the same.
|
|
||||||
return 'cssTransform';
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const camelcase = require('camelcase');
|
|
||||||
|
|
||||||
// This is a custom Jest transformer turning file imports into filenames.
|
|
||||||
// http://facebook.github.io/jest/docs/en/webpack.html
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
process(src, filename) {
|
|
||||||
const assetFilename = JSON.stringify(path.basename(filename));
|
|
||||||
|
|
||||||
if (filename.match(/\.svg$/)) {
|
|
||||||
// Based on how SVGR generates a component name:
|
|
||||||
// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
|
|
||||||
const pascalCaseFilename = camelcase(path.parse(filename).name, {
|
|
||||||
pascalCase: true,
|
|
||||||
});
|
|
||||||
const componentName = `Svg${pascalCaseFilename}`;
|
|
||||||
return `const React = require('react');
|
|
||||||
module.exports = {
|
|
||||||
__esModule: true,
|
|
||||||
default: ${assetFilename},
|
|
||||||
ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
|
|
||||||
return {
|
|
||||||
$$typeof: Symbol.for('react.element'),
|
|
||||||
type: 'svg',
|
|
||||||
ref: ref,
|
|
||||||
key: null,
|
|
||||||
props: Object.assign({}, props, {
|
|
||||||
children: ${assetFilename}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `module.exports = ${assetFilename};`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const paths = require('./paths');
|
|
||||||
const chalk = require('react-dev-utils/chalk');
|
|
||||||
const resolve = require('resolve');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get additional module paths based on the baseUrl of a compilerOptions object.
|
|
||||||
*
|
|
||||||
* @param {Object} options
|
|
||||||
*/
|
|
||||||
function getAdditionalModulePaths(options = {}) {
|
|
||||||
const baseUrl = options.baseUrl;
|
|
||||||
|
|
||||||
// We need to explicitly check for null and undefined (and not a falsy value) because
|
|
||||||
// TypeScript treats an empty string as `.`.
|
|
||||||
if (baseUrl == null) {
|
|
||||||
// If there's no baseUrl set we respect NODE_PATH
|
|
||||||
// Note that NODE_PATH is deprecated and will be removed
|
|
||||||
// in the next major release of create-react-app.
|
|
||||||
|
|
||||||
const nodePath = process.env.NODE_PATH || '';
|
|
||||||
return nodePath.split(path.delimiter).filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
|
||||||
|
|
||||||
// We don't need to do anything if `baseUrl` is set to `node_modules`. This is
|
|
||||||
// the default behavior.
|
|
||||||
if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow the user set the `baseUrl` to `appSrc`.
|
|
||||||
if (path.relative(paths.appSrc, baseUrlResolved) === '') {
|
|
||||||
return [paths.appSrc];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the path is equal to the root directory we ignore it here.
|
|
||||||
// We don't want to allow importing from the root directly as source files are
|
|
||||||
// not transpiled outside of `src`. We do allow importing them with the
|
|
||||||
// absolute path (e.g. `src/Components/Button.js`) but we set that up with
|
|
||||||
// an alias.
|
|
||||||
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, throw an error.
|
|
||||||
throw new Error(
|
|
||||||
chalk.red.bold(
|
|
||||||
"Your project's `baseUrl` can only be set to `src` or `node_modules`." +
|
|
||||||
' Create React App does not support other values at this time.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get webpack aliases based on the baseUrl of a compilerOptions object.
|
|
||||||
*
|
|
||||||
* @param {*} options
|
|
||||||
*/
|
|
||||||
function getWebpackAliases(options = {}) {
|
|
||||||
const baseUrl = options.baseUrl;
|
|
||||||
|
|
||||||
if (!baseUrl) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
|
||||||
|
|
||||||
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
|
||||||
return {
|
|
||||||
src: paths.appSrc,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get jest aliases based on the baseUrl of a compilerOptions object.
|
|
||||||
*
|
|
||||||
* @param {*} options
|
|
||||||
*/
|
|
||||||
function getJestAliases(options = {}) {
|
|
||||||
const baseUrl = options.baseUrl;
|
|
||||||
|
|
||||||
if (!baseUrl) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
|
||||||
|
|
||||||
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
|
||||||
return {
|
|
||||||
'^src/(.*)$': '<rootDir>/src/$1',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getModules() {
|
|
||||||
// Check if TypeScript is setup
|
|
||||||
const hasTsConfig = fs.existsSync(paths.appTsConfig);
|
|
||||||
const hasJsConfig = fs.existsSync(paths.appJsConfig);
|
|
||||||
|
|
||||||
if (hasTsConfig && hasJsConfig) {
|
|
||||||
throw new Error(
|
|
||||||
'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let config;
|
|
||||||
|
|
||||||
// If there's a tsconfig.json we assume it's a
|
|
||||||
// TypeScript project and set up the config
|
|
||||||
// based on tsconfig.json
|
|
||||||
if (hasTsConfig) {
|
|
||||||
const ts = require(resolve.sync('typescript', {
|
|
||||||
basedir: paths.appNodeModules,
|
|
||||||
}));
|
|
||||||
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
|
|
||||||
// Otherwise we'll check if there is jsconfig.json
|
|
||||||
// for non TS projects.
|
|
||||||
} else if (hasJsConfig) {
|
|
||||||
config = require(paths.appJsConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
config = config || {};
|
|
||||||
const options = config.compilerOptions || {};
|
|
||||||
|
|
||||||
const additionalModulePaths = getAdditionalModulePaths(options);
|
|
||||||
|
|
||||||
return {
|
|
||||||
additionalModulePaths: additionalModulePaths,
|
|
||||||
webpackAliases: getWebpackAliases(options),
|
|
||||||
jestAliases: getJestAliases(options),
|
|
||||||
hasTsConfig,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = getModules();
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
|
|
||||||
|
|
||||||
// Make sure any symlinks in the project folder are resolved:
|
|
||||||
// https://github.com/facebook/create-react-app/issues/637
|
|
||||||
const appDirectory = fs.realpathSync(process.cwd());
|
|
||||||
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
|
|
||||||
const templateDirectory = fs.realpathSync(__dirname);
|
|
||||||
const resolveTemplate = relativePath => path.resolve(templateDirectory, '..', relativePath);
|
|
||||||
|
|
||||||
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
|
|
||||||
// "public path" at which the app is served.
|
|
||||||
// webpack needs to know it to put the right <script> hrefs into HTML even in
|
|
||||||
// single-page apps that may serve index.html for nested URLs like /todos/42.
|
|
||||||
// We can't use a relative path in HTML because we don't want to load something
|
|
||||||
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
|
|
||||||
const publicUrlOrPath = getPublicUrlOrPath(
|
|
||||||
process.env.NODE_ENV === 'development',
|
|
||||||
require(resolveApp('package.json')).homepage,
|
|
||||||
process.env.PUBLIC_URL
|
|
||||||
);
|
|
||||||
|
|
||||||
const moduleFileExtensions = [
|
|
||||||
'web.mjs',
|
|
||||||
'mjs',
|
|
||||||
'web.js',
|
|
||||||
'js',
|
|
||||||
'web.ts',
|
|
||||||
'ts',
|
|
||||||
'web.tsx',
|
|
||||||
'tsx',
|
|
||||||
'json',
|
|
||||||
'web.jsx',
|
|
||||||
'jsx',
|
|
||||||
];
|
|
||||||
|
|
||||||
// Resolve file paths in the same order as webpack
|
|
||||||
const resolveModule = (resolveFn, filePath) => {
|
|
||||||
const extension = moduleFileExtensions.find(extension =>
|
|
||||||
fs.existsSync(resolveFn(`${filePath}.${extension}`))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (extension) {
|
|
||||||
return resolveFn(`${filePath}.${extension}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolveFn(`${filePath}.js`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// config after eject: we're in ./config/
|
|
||||||
module.exports = {
|
|
||||||
dotenv: resolveApp('.env'),
|
|
||||||
appPath: resolveApp('.'),
|
|
||||||
appBuild: resolveApp('build'),
|
|
||||||
appPublic: resolveTemplate('public'),
|
|
||||||
appHtml: resolveTemplate('public/index.html'),
|
|
||||||
appIndexJs: resolveModule(resolveApp, 'src/index'),
|
|
||||||
appPackageJson: resolveApp('package.json'),
|
|
||||||
appSrc: resolveApp('src'),
|
|
||||||
templateSrc: resolveTemplate('src'),
|
|
||||||
appTsConfig: resolveTemplate('tsconfig.json'),
|
|
||||||
appJsConfig: resolveTemplate('jsconfig.json'),
|
|
||||||
yarnLockFile: resolveApp('yarn.lock'),
|
|
||||||
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
|
|
||||||
proxySetup: resolveTemplate('src/setupProxy.js'),
|
|
||||||
appNodeModules: resolveApp('node_modules'),
|
|
||||||
publicUrlOrPath,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports.moduleFileExtensions = moduleFileExtensions;
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const { resolveModuleName } = require('ts-pnp');
|
|
||||||
|
|
||||||
exports.resolveModuleName = (
|
|
||||||
typescript,
|
|
||||||
moduleName,
|
|
||||||
containingFile,
|
|
||||||
compilerOptions,
|
|
||||||
resolutionHost
|
|
||||||
) => {
|
|
||||||
return resolveModuleName(
|
|
||||||
moduleName,
|
|
||||||
containingFile,
|
|
||||||
compilerOptions,
|
|
||||||
resolutionHost,
|
|
||||||
typescript.resolveModuleName
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.resolveTypeReferenceDirective = (
|
|
||||||
typescript,
|
|
||||||
moduleName,
|
|
||||||
containingFile,
|
|
||||||
compilerOptions,
|
|
||||||
resolutionHost
|
|
||||||
) => {
|
|
||||||
return resolveModuleName(
|
|
||||||
moduleName,
|
|
||||||
containingFile,
|
|
||||||
compilerOptions,
|
|
||||||
resolutionHost,
|
|
||||||
typescript.resolveTypeReferenceDirective
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,670 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const resolve = require('resolve');
|
|
||||||
const PnpWebpackPlugin = require('pnp-webpack-plugin');
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
|
|
||||||
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
|
|
||||||
const TerserPlugin = require('terser-webpack-plugin');
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
||||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
|
||||||
const safePostCssParser = require('postcss-safe-parser');
|
|
||||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
|
||||||
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
|
|
||||||
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
|
|
||||||
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
|
|
||||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
|
||||||
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
|
|
||||||
const paths = require('./paths');
|
|
||||||
const modules = require('./modules');
|
|
||||||
const getClientEnvironment = require('./env');
|
|
||||||
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
|
|
||||||
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
|
|
||||||
const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
|
|
||||||
|
|
||||||
const postcssNormalize = require('postcss-normalize');
|
|
||||||
|
|
||||||
const appPackageJson = require(paths.appPackageJson);
|
|
||||||
|
|
||||||
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
|
||||||
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
|
|
||||||
// Some apps do not need the benefits of saving a web request, so not inlining the chunk
|
|
||||||
// makes for a smoother build process.
|
|
||||||
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
|
|
||||||
|
|
||||||
const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true';
|
|
||||||
|
|
||||||
const imageInlineSizeLimit = parseInt(
|
|
||||||
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check if TypeScript is setup
|
|
||||||
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
|
||||||
|
|
||||||
// style files regexes
|
|
||||||
const cssRegex = /\.css$/;
|
|
||||||
const cssModuleRegex = /\.module\.css$/;
|
|
||||||
const sassRegex = /\.(scss|sass)$/;
|
|
||||||
const sassModuleRegex = /\.module\.(scss|sass)$/;
|
|
||||||
|
|
||||||
// This is the production and development configuration.
|
|
||||||
// It is focused on developer experience, fast rebuilds, and a minimal bundle.
|
|
||||||
module.exports = function(webpackEnv) {
|
|
||||||
const isEnvDevelopment = webpackEnv === 'development';
|
|
||||||
const isEnvProduction = webpackEnv === 'production';
|
|
||||||
|
|
||||||
// Variable used for enabling profiling in Production
|
|
||||||
// passed into alias object. Uses a flag if passed into the build command
|
|
||||||
const isEnvProductionProfile =
|
|
||||||
isEnvProduction && process.argv.includes('--profile');
|
|
||||||
|
|
||||||
// We will provide `paths.publicUrlOrPath` to our app
|
|
||||||
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
|
||||||
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
|
||||||
// Get environment variables to inject into our app.
|
|
||||||
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
|
||||||
|
|
||||||
// common function to get style loaders
|
|
||||||
const getStyleLoaders = (cssOptions, preProcessor) => {
|
|
||||||
const loaders = [
|
|
||||||
isEnvDevelopment && require.resolve('style-loader'),
|
|
||||||
isEnvProduction && {
|
|
||||||
loader: MiniCssExtractPlugin.loader,
|
|
||||||
// css is located in `static/css`, use '../../' to locate index.html folder
|
|
||||||
// in production `paths.publicUrlOrPath` can be a relative path
|
|
||||||
options: paths.publicUrlOrPath.startsWith('.')
|
|
||||||
? { publicPath: '../../' }
|
|
||||||
: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: require.resolve('css-loader'),
|
|
||||||
options: cssOptions,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Options for PostCSS as we reference these options twice
|
|
||||||
// Adds vendor prefixing based on your specified browser support in
|
|
||||||
// package.json
|
|
||||||
loader: require.resolve('postcss-loader'),
|
|
||||||
options: {
|
|
||||||
// Necessary for external CSS imports to work
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2677
|
|
||||||
ident: 'postcss',
|
|
||||||
plugins: () => [
|
|
||||||
require('postcss-flexbugs-fixes'),
|
|
||||||
require('postcss-preset-env')({
|
|
||||||
autoprefixer: {
|
|
||||||
flexbox: 'no-2009',
|
|
||||||
},
|
|
||||||
stage: 3,
|
|
||||||
}),
|
|
||||||
// Adds PostCSS Normalize as the reset css with default options,
|
|
||||||
// so that it honors browserslist config in package.json
|
|
||||||
// which in turn let's users customize the target behavior as per their needs.
|
|
||||||
postcssNormalize(),
|
|
||||||
],
|
|
||||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
].filter(Boolean);
|
|
||||||
if (preProcessor) {
|
|
||||||
loaders.push(
|
|
||||||
{
|
|
||||||
loader: require.resolve('resolve-url-loader'),
|
|
||||||
options: {
|
|
||||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: require.resolve(preProcessor),
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return loaders;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
|
|
||||||
// Stop compilation early in production
|
|
||||||
bail: isEnvProduction,
|
|
||||||
devtool: isEnvProduction
|
|
||||||
? shouldUseSourceMap
|
|
||||||
? 'source-map'
|
|
||||||
: false
|
|
||||||
: isEnvDevelopment && 'cheap-module-source-map',
|
|
||||||
// These are the "entry points" to our application.
|
|
||||||
// This means they will be the "root" imports that are included in JS bundle.
|
|
||||||
entry: [
|
|
||||||
// Include an alternative client for WebpackDevServer. A client's job is to
|
|
||||||
// connect to WebpackDevServer by a socket and get notified about changes.
|
|
||||||
// When you save a file, the client will either apply hot updates (in case
|
|
||||||
// of CSS changes), or refresh the page (in case of JS changes). When you
|
|
||||||
// make a syntax error, this client will display a syntax error overlay.
|
|
||||||
// Note: instead of the default WebpackDevServer client, we use a custom one
|
|
||||||
// to bring better experience for Create React App users. You can replace
|
|
||||||
// the line below with these two lines if you prefer the stock client:
|
|
||||||
// require.resolve('webpack-dev-server/client') + '?/',
|
|
||||||
// require.resolve('webpack/hot/dev-server'),
|
|
||||||
isEnvDevelopment &&
|
|
||||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
|
||||||
// Finally, this is your app's code:
|
|
||||||
paths.appIndexJs,
|
|
||||||
// We include the app code last so that if there is a runtime error during
|
|
||||||
// initialization, it doesn't blow up the WebpackDevServer client, and
|
|
||||||
// changing JS code would still trigger a refresh.
|
|
||||||
].filter(Boolean),
|
|
||||||
output: {
|
|
||||||
// The build folder.
|
|
||||||
path: isEnvProduction ? paths.appBuild : undefined,
|
|
||||||
// Add /* filename */ comments to generated require()s in the output.
|
|
||||||
pathinfo: isEnvDevelopment,
|
|
||||||
// There will be one main bundle, and one file per asynchronous chunk.
|
|
||||||
// In development, it does not produce real files.
|
|
||||||
filename: isEnvProduction
|
|
||||||
? 'static/js/[name].[contenthash:8].js'
|
|
||||||
: isEnvDevelopment && 'static/js/bundle.js',
|
|
||||||
// TODO: remove this when upgrading to webpack 5
|
|
||||||
futureEmitAssets: true,
|
|
||||||
// There are also additional JS chunk files if you use code splitting.
|
|
||||||
chunkFilename: isEnvProduction
|
|
||||||
? 'static/js/[name].[contenthash:8].chunk.js'
|
|
||||||
: isEnvDevelopment && 'static/js/[name].chunk.js',
|
|
||||||
// webpack uses `publicPath` to determine where the app is being served from.
|
|
||||||
// It requires a trailing slash, or the file assets will get an incorrect path.
|
|
||||||
// We inferred the "public path" (such as / or /my-project) from homepage.
|
|
||||||
publicPath: paths.publicUrlOrPath,
|
|
||||||
// Point sourcemap entries to original disk location (format as URL on Windows)
|
|
||||||
devtoolModuleFilenameTemplate: isEnvProduction
|
|
||||||
? info =>
|
|
||||||
path
|
|
||||||
.relative(paths.appSrc, info.absoluteResourcePath)
|
|
||||||
.replace(/\\/g, '/')
|
|
||||||
: isEnvDevelopment &&
|
|
||||||
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
|
|
||||||
// Prevents conflicts when multiple webpack runtimes (from different apps)
|
|
||||||
// are used on the same page.
|
|
||||||
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
|
|
||||||
// this defaults to 'window', but by setting it to 'this' then
|
|
||||||
// module chunks which are built will work in web workers as well.
|
|
||||||
globalObject: 'this',
|
|
||||||
},
|
|
||||||
optimization: {
|
|
||||||
minimize: isEnvProduction,
|
|
||||||
minimizer: [
|
|
||||||
// This is only used in production mode
|
|
||||||
new TerserPlugin({
|
|
||||||
terserOptions: {
|
|
||||||
parse: {
|
|
||||||
// We want terser to parse ecma 8 code. However, we don't want it
|
|
||||||
// to apply any minification steps that turns valid ecma 5 code
|
|
||||||
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
|
||||||
// sections only apply transformations that are ecma 5 safe
|
|
||||||
// https://github.com/facebook/create-react-app/pull/4234
|
|
||||||
ecma: 8,
|
|
||||||
},
|
|
||||||
compress: {
|
|
||||||
ecma: 5,
|
|
||||||
warnings: false,
|
|
||||||
// Disabled because of an issue with Uglify breaking seemingly valid code:
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2376
|
|
||||||
// Pending further investigation:
|
|
||||||
// https://github.com/mishoo/UglifyJS2/issues/2011
|
|
||||||
comparisons: false,
|
|
||||||
// Disabled because of an issue with Terser breaking valid code:
|
|
||||||
// https://github.com/facebook/create-react-app/issues/5250
|
|
||||||
// Pending further investigation:
|
|
||||||
// https://github.com/terser-js/terser/issues/120
|
|
||||||
inline: 2,
|
|
||||||
},
|
|
||||||
mangle: {
|
|
||||||
safari10: true,
|
|
||||||
},
|
|
||||||
// Added for profiling in devtools
|
|
||||||
keep_classnames: isEnvProductionProfile,
|
|
||||||
keep_fnames: isEnvProductionProfile,
|
|
||||||
output: {
|
|
||||||
ecma: 5,
|
|
||||||
comments: false,
|
|
||||||
// Turned on because emoji and regex is not minified properly using default
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2488
|
|
||||||
ascii_only: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sourceMap: shouldUseSourceMap,
|
|
||||||
}),
|
|
||||||
// This is only used in production mode
|
|
||||||
new OptimizeCSSAssetsPlugin({
|
|
||||||
cssProcessorOptions: {
|
|
||||||
parser: safePostCssParser,
|
|
||||||
map: shouldUseSourceMap
|
|
||||||
? {
|
|
||||||
// `inline: false` forces the sourcemap to be output into a
|
|
||||||
// separate file
|
|
||||||
inline: false,
|
|
||||||
// `annotation: true` appends the sourceMappingURL to the end of
|
|
||||||
// the css file, helping the browser find the sourcemap
|
|
||||||
annotation: true,
|
|
||||||
}
|
|
||||||
: false,
|
|
||||||
},
|
|
||||||
cssProcessorPluginOptions: {
|
|
||||||
preset: ['default', { minifyFontValues: { removeQuotes: false } }],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
// Automatically split vendor and commons
|
|
||||||
// https://twitter.com/wSokra/status/969633336732905474
|
|
||||||
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
|
||||||
splitChunks: {
|
|
||||||
chunks: 'all',
|
|
||||||
name: false,
|
|
||||||
},
|
|
||||||
// Keep the runtime chunk separated to enable long term caching
|
|
||||||
// https://twitter.com/wSokra/status/969679223278505985
|
|
||||||
// https://github.com/facebook/create-react-app/issues/5358
|
|
||||||
runtimeChunk: {
|
|
||||||
name: entrypoint => `runtime-${entrypoint.name}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
// This allows you to set a fallback for where webpack should look for modules.
|
|
||||||
// We placed these paths second because we want `node_modules` to "win"
|
|
||||||
// if there are any conflicts. This matches Node resolution mechanism.
|
|
||||||
// https://github.com/facebook/create-react-app/issues/253
|
|
||||||
modules: ['node_modules', paths.appNodeModules].concat(
|
|
||||||
modules.additionalModulePaths || []
|
|
||||||
),
|
|
||||||
// These are the reasonable defaults supported by the Node ecosystem.
|
|
||||||
// We also include JSX as a common component filename extension to support
|
|
||||||
// some tools, although we do not recommend using it, see:
|
|
||||||
// https://github.com/facebook/create-react-app/issues/290
|
|
||||||
// `web` extension prefixes have been added for better support
|
|
||||||
// for React Native Web.
|
|
||||||
extensions: paths.moduleFileExtensions
|
|
||||||
.map(ext => `.${ext}`)
|
|
||||||
.filter(ext => useTypeScript || !ext.includes('ts')),
|
|
||||||
alias: {
|
|
||||||
// Support React Native Web
|
|
||||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
|
||||||
'react-native': 'react-native-web',
|
|
||||||
// Allows for better profiling with ReactDevTools
|
|
||||||
...(isEnvProductionProfile && {
|
|
||||||
'react-dom$': 'react-dom/profiling',
|
|
||||||
'scheduler/tracing': 'scheduler/tracing-profiling',
|
|
||||||
}),
|
|
||||||
...(modules.webpackAliases || {}),
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
|
||||||
// guards against forgotten dependencies and such.
|
|
||||||
PnpWebpackPlugin,
|
|
||||||
// Prevents users from importing files from outside of src/ (or node_modules/).
|
|
||||||
// This often causes confusion because we only process files within src/ with babel.
|
|
||||||
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
|
||||||
// please link the files into your node_modules/ and let module-resolution kick in.
|
|
||||||
// Make sure your source files are compiled, as they will not be processed in any way.
|
|
||||||
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
resolveLoader: {
|
|
||||||
plugins: [
|
|
||||||
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders
|
|
||||||
// from the current package.
|
|
||||||
PnpWebpackPlugin.moduleLoader(module),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
strictExportPresence: true,
|
|
||||||
rules: [
|
|
||||||
// Disable require.ensure as it's not a standard language feature.
|
|
||||||
{ parser: { requireEnsure: false } },
|
|
||||||
|
|
||||||
// First, run the linter.
|
|
||||||
// It's important to do this before Babel processes the JS.
|
|
||||||
// {
|
|
||||||
// test: /\.(js|mjs|jsx|ts|tsx)$/,
|
|
||||||
// enforce: 'pre',
|
|
||||||
// use: [
|
|
||||||
// {
|
|
||||||
// options: {
|
|
||||||
// cache: true,
|
|
||||||
// formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
|
||||||
// eslintPath: require.resolve('eslint'),
|
|
||||||
// resolvePluginsRelativeTo: __dirname,
|
|
||||||
// },
|
|
||||||
// loader: require.resolve('eslint-loader'),
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// include: paths.appSrc,
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
// "oneOf" will traverse all following loaders until one will
|
|
||||||
// match the requirements. When no loader matches it will fall
|
|
||||||
// back to the "file" loader at the end of the loader list.
|
|
||||||
oneOf: [
|
|
||||||
// "url" loader works like "file" loader except that it embeds assets
|
|
||||||
// smaller than specified limit in bytes as data URLs to avoid requests.
|
|
||||||
// A missing `test` is equivalent to a match.
|
|
||||||
{
|
|
||||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
|
||||||
loader: require.resolve('url-loader'),
|
|
||||||
options: {
|
|
||||||
limit: imageInlineSizeLimit,
|
|
||||||
name: 'static/media/[name].[hash:8].[ext]',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Process application JS with Babel.
|
|
||||||
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
|
|
||||||
{
|
|
||||||
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
|
||||||
include: [paths.appSrc, paths.templateSrc],
|
|
||||||
loader: require.resolve('babel-loader'),
|
|
||||||
options: {
|
|
||||||
customize: require.resolve(
|
|
||||||
'babel-preset-react-app/webpack-overrides'
|
|
||||||
),
|
|
||||||
|
|
||||||
presets:['react-app'],
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
[
|
|
||||||
require.resolve('babel-plugin-named-asset-import'),
|
|
||||||
{
|
|
||||||
loaderMap: {
|
|
||||||
svg: {
|
|
||||||
ReactComponent:
|
|
||||||
'@svgr/webpack?-svgo,+titleProp,+ref![path]',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
// This is a feature of `babel-loader` for webpack (not Babel itself).
|
|
||||||
// It enables caching results in ./node_modules/.cache/babel-loader/
|
|
||||||
// directory for faster rebuilds.
|
|
||||||
cacheDirectory: true,
|
|
||||||
// See #6846 for context on why cacheCompression is disabled
|
|
||||||
cacheCompression: false,
|
|
||||||
compact: isEnvProduction,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Process any JS outside of the app with Babel.
|
|
||||||
// Unlike the application JS, we only compile the standard ES features.
|
|
||||||
{
|
|
||||||
test: /\.(js|mjs)$/,
|
|
||||||
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
|
||||||
loader: require.resolve('babel-loader'),
|
|
||||||
options: {
|
|
||||||
babelrc: false,
|
|
||||||
configFile: false,
|
|
||||||
compact: false,
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
require.resolve('babel-preset-react-app/dependencies'),
|
|
||||||
{ helpers: true },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
cacheDirectory: true,
|
|
||||||
// See #6846 for context on why cacheCompression is disabled
|
|
||||||
cacheCompression: false,
|
|
||||||
|
|
||||||
// Babel sourcemaps are needed for debugging into node_modules
|
|
||||||
// code. Without the options below, debuggers like VSCode
|
|
||||||
// show incorrect code and set breakpoints on the wrong lines.
|
|
||||||
sourceMaps: shouldUseSourceMap,
|
|
||||||
inputSourceMap: shouldUseSourceMap,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// "postcss" loader applies autoprefixer to our CSS.
|
|
||||||
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
|
||||||
// "style" loader turns CSS into JS modules that inject <style> tags.
|
|
||||||
// In production, we use MiniCSSExtractPlugin to extract that CSS
|
|
||||||
// to a file, but in development "style" loader enables hot editing
|
|
||||||
// of CSS.
|
|
||||||
// By default we support CSS Modules with the extension .module.css
|
|
||||||
{
|
|
||||||
test: cssRegex,
|
|
||||||
exclude: cssModuleRegex,
|
|
||||||
use: getStyleLoaders({
|
|
||||||
importLoaders: 1,
|
|
||||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
|
||||||
}),
|
|
||||||
// Don't consider CSS imports dead code even if the
|
|
||||||
// containing package claims to have no side effects.
|
|
||||||
// Remove this when webpack adds a warning or an error for this.
|
|
||||||
// See https://github.com/webpack/webpack/issues/6571
|
|
||||||
sideEffects: true,
|
|
||||||
},
|
|
||||||
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
|
||||||
// using the extension .module.css
|
|
||||||
{
|
|
||||||
test: cssModuleRegex,
|
|
||||||
use: getStyleLoaders({
|
|
||||||
importLoaders: 1,
|
|
||||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
|
||||||
modules: {
|
|
||||||
getLocalIdent: getCSSModuleLocalIdent,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
// Opt-in support for SASS (using .scss or .sass extensions).
|
|
||||||
// By default we support SASS Modules with the
|
|
||||||
// extensions .module.scss or .module.sass
|
|
||||||
{
|
|
||||||
test: sassRegex,
|
|
||||||
exclude: sassModuleRegex,
|
|
||||||
use: getStyleLoaders(
|
|
||||||
{
|
|
||||||
importLoaders: 3,
|
|
||||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
|
||||||
},
|
|
||||||
'sass-loader'
|
|
||||||
),
|
|
||||||
// Don't consider CSS imports dead code even if the
|
|
||||||
// containing package claims to have no side effects.
|
|
||||||
// Remove this when webpack adds a warning or an error for this.
|
|
||||||
// See https://github.com/webpack/webpack/issues/6571
|
|
||||||
sideEffects: true,
|
|
||||||
},
|
|
||||||
// Adds support for CSS Modules, but using SASS
|
|
||||||
// using the extension .module.scss or .module.sass
|
|
||||||
{
|
|
||||||
test: sassModuleRegex,
|
|
||||||
use: getStyleLoaders(
|
|
||||||
{
|
|
||||||
importLoaders: 3,
|
|
||||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
|
||||||
modules: {
|
|
||||||
getLocalIdent: getCSSModuleLocalIdent,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'sass-loader'
|
|
||||||
),
|
|
||||||
},
|
|
||||||
// "file" loader makes sure those assets get served by WebpackDevServer.
|
|
||||||
// When you `import` an asset, you get its (virtual) filename.
|
|
||||||
// In production, they would get copied to the `build` folder.
|
|
||||||
// This loader doesn't use a "test" so it will catch all modules
|
|
||||||
// that fall through the other loaders.
|
|
||||||
{
|
|
||||||
loader: require.resolve('file-loader'),
|
|
||||||
// Exclude `js` files to keep "css" loader working as it injects
|
|
||||||
// its runtime that would otherwise be processed through "file" loader.
|
|
||||||
// Also exclude `html` and `json` extensions so they get processed
|
|
||||||
// by webpacks internal loaders.
|
|
||||||
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
|
|
||||||
options: {
|
|
||||||
name: 'static/media/[name].[hash:8].[ext]',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// ** STOP ** Are you adding a new loader?
|
|
||||||
// Make sure to add the new loader(s) before the "file" loader.
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
// Generates an `index.html` file with the <script> injected.
|
|
||||||
new HtmlWebpackPlugin(
|
|
||||||
Object.assign(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
inject: true,
|
|
||||||
template: paths.appHtml,
|
|
||||||
},
|
|
||||||
isEnvProduction
|
|
||||||
? {
|
|
||||||
minify: {
|
|
||||||
removeComments: true,
|
|
||||||
collapseWhitespace: true,
|
|
||||||
removeRedundantAttributes: true,
|
|
||||||
useShortDoctype: true,
|
|
||||||
removeEmptyAttributes: true,
|
|
||||||
removeStyleLinkTypeAttributes: true,
|
|
||||||
keepClosingSlash: true,
|
|
||||||
minifyJS: true,
|
|
||||||
minifyCSS: true,
|
|
||||||
minifyURLs: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
)
|
|
||||||
),
|
|
||||||
// Inlines the webpack runtime script. This script is too small to warrant
|
|
||||||
// a network request.
|
|
||||||
// https://github.com/facebook/create-react-app/issues/5358
|
|
||||||
isEnvProduction &&
|
|
||||||
shouldInlineRuntimeChunk &&
|
|
||||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
|
|
||||||
// Makes some environment variables available in index.html.
|
|
||||||
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
|
||||||
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
|
||||||
// It will be an empty string unless you specify "homepage"
|
|
||||||
// in `package.json`, in which case it will be the pathname of that URL.
|
|
||||||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
|
||||||
// This gives some necessary context to module not found errors, such as
|
|
||||||
// the requesting resource.
|
|
||||||
new ModuleNotFoundPlugin(paths.appPath),
|
|
||||||
// Makes some environment variables available to the JS code, for example:
|
|
||||||
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
|
|
||||||
// It is absolutely essential that NODE_ENV is set to production
|
|
||||||
// during a production build.
|
|
||||||
// Otherwise React will be compiled in the very slow development mode.
|
|
||||||
new webpack.DefinePlugin(env.stringified),
|
|
||||||
// This is necessary to emit hot updates (currently CSS only):
|
|
||||||
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
|
|
||||||
// Watcher doesn't work well if you mistype casing in a path so we use
|
|
||||||
// a plugin that prints an error when you attempt to do this.
|
|
||||||
// See https://github.com/facebook/create-react-app/issues/240
|
|
||||||
isEnvDevelopment && new CaseSensitivePathsPlugin(),
|
|
||||||
// If you require a missing module and then `npm install` it, you still have
|
|
||||||
// to restart the development server for webpack to discover it. This plugin
|
|
||||||
// makes the discovery automatic so you don't have to restart.
|
|
||||||
// See https://github.com/facebook/create-react-app/issues/186
|
|
||||||
isEnvDevelopment &&
|
|
||||||
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
|
|
||||||
isEnvProduction &&
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
// Options similar to the same options in webpackOptions.output
|
|
||||||
// both options are optional
|
|
||||||
filename: 'static/css/[name].[contenthash:8].css',
|
|
||||||
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
|
|
||||||
}),
|
|
||||||
// Generate an asset manifest file with the following content:
|
|
||||||
// - "files" key: Mapping of all asset filenames to their corresponding
|
|
||||||
// output file so that tools can pick it up without having to parse
|
|
||||||
// `index.html`
|
|
||||||
// - "entrypoints" key: Array of files which are included in `index.html`,
|
|
||||||
// can be used to reconstruct the HTML if necessary
|
|
||||||
new ManifestPlugin({
|
|
||||||
fileName: 'asset-manifest.json',
|
|
||||||
publicPath: paths.publicUrlOrPath,
|
|
||||||
generate: (seed, files, entrypoints) => {
|
|
||||||
const manifestFiles = files.reduce((manifest, file) => {
|
|
||||||
manifest[file.name] = file.path;
|
|
||||||
return manifest;
|
|
||||||
}, seed);
|
|
||||||
const entrypointFiles = entrypoints.main.filter(
|
|
||||||
fileName => !fileName.endsWith('.map')
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
files: manifestFiles,
|
|
||||||
entrypoints: entrypointFiles,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
// Moment.js is an extremely popular library that bundles large locale files
|
|
||||||
// by default due to how webpack interprets its code. This is a practical
|
|
||||||
// solution that requires the user to opt into importing specific locales.
|
|
||||||
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
|
||||||
// You can remove this if you don't use Moment.js:
|
|
||||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
|
||||||
// Generate a service worker script that will precache, and keep up to date,
|
|
||||||
// the HTML & assets that are part of the webpack build.
|
|
||||||
isEnvProduction &&
|
|
||||||
new WorkboxWebpackPlugin.GenerateSW({
|
|
||||||
clientsClaim: true,
|
|
||||||
exclude: [/\.map$/, /asset-manifest\.json$/],
|
|
||||||
importWorkboxFrom: 'cdn',
|
|
||||||
navigateFallback: paths.publicUrlOrPath + 'index.html',
|
|
||||||
navigateFallbackBlacklist: [
|
|
||||||
// Exclude URLs starting with /_, as they're likely an API call
|
|
||||||
new RegExp('^/_'),
|
|
||||||
// Exclude any URLs whose last part seems to be a file extension
|
|
||||||
// as they're likely a resource and not a SPA route.
|
|
||||||
// URLs containing a "?" character won't be blacklisted as they're likely
|
|
||||||
// a route with query params (e.g. auth callbacks).
|
|
||||||
new RegExp('/[^/?]+\\.[^/]+$'),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
// TypeScript type checking
|
|
||||||
useTypeScript &&
|
|
||||||
new ForkTsCheckerWebpackPlugin({
|
|
||||||
typescript: resolve.sync('typescript', {
|
|
||||||
basedir: paths.appNodeModules,
|
|
||||||
}),
|
|
||||||
async: isEnvDevelopment,
|
|
||||||
useTypescriptIncrementalApi: true,
|
|
||||||
checkSyntacticErrors: true,
|
|
||||||
resolveModuleNameModule: process.versions.pnp
|
|
||||||
? `${__dirname}/pnpTs.js`
|
|
||||||
: undefined,
|
|
||||||
resolveTypeReferenceDirectiveModule: process.versions.pnp
|
|
||||||
? `${__dirname}/pnpTs.js`
|
|
||||||
: undefined,
|
|
||||||
tsconfig: paths.appTsConfig,
|
|
||||||
reportFiles: [
|
|
||||||
'**',
|
|
||||||
'!**/__tests__/**',
|
|
||||||
'!**/?(*.)(spec|test).*',
|
|
||||||
'!**/src/setupProxy.*',
|
|
||||||
'!**/src/setupTests.*',
|
|
||||||
],
|
|
||||||
silent: true,
|
|
||||||
// The formatter is invoked directly in WebpackDevServerUtils during development
|
|
||||||
formatter: isEnvProduction ? typescriptFormatter : undefined,
|
|
||||||
}),
|
|
||||||
].filter(Boolean),
|
|
||||||
// Some libraries import Node modules but don't use them in the browser.
|
|
||||||
// Tell webpack to provide empty mocks for them so importing them works.
|
|
||||||
node: {
|
|
||||||
module: 'empty',
|
|
||||||
dgram: 'empty',
|
|
||||||
dns: 'mock',
|
|
||||||
fs: 'empty',
|
|
||||||
http2: 'empty',
|
|
||||||
net: 'empty',
|
|
||||||
tls: 'empty',
|
|
||||||
child_process: 'empty',
|
|
||||||
},
|
|
||||||
// Turn off performance processing because we utilize
|
|
||||||
// our own hints via the FileSizeReporter
|
|
||||||
performance: false,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
|
|
||||||
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
|
|
||||||
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
|
|
||||||
const ignoredFiles = require('react-dev-utils/ignoredFiles');
|
|
||||||
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
|
|
||||||
const paths = require('./paths');
|
|
||||||
const getHttpsConfig = require('./getHttpsConfig');
|
|
||||||
|
|
||||||
const host = process.env.HOST || '0.0.0.0';
|
|
||||||
const sockHost = process.env.WDS_SOCKET_HOST;
|
|
||||||
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/sockjs-node'
|
|
||||||
const sockPort = process.env.WDS_SOCKET_PORT;
|
|
||||||
|
|
||||||
module.exports = function(proxy, allowedHost) {
|
|
||||||
return {
|
|
||||||
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
|
|
||||||
// websites from potentially accessing local content through DNS rebinding:
|
|
||||||
// https://github.com/webpack/webpack-dev-server/issues/887
|
|
||||||
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
|
|
||||||
// However, it made several existing use cases such as development in cloud
|
|
||||||
// environment or subdomains in development significantly more complicated:
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2271
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2233
|
|
||||||
// While we're investigating better solutions, for now we will take a
|
|
||||||
// compromise. Since our WDS configuration only serves files in the `public`
|
|
||||||
// folder we won't consider accessing them a vulnerability. However, if you
|
|
||||||
// use the `proxy` feature, it gets more dangerous because it can expose
|
|
||||||
// remote code execution vulnerabilities in backends like Django and Rails.
|
|
||||||
// So we will disable the host check normally, but enable it if you have
|
|
||||||
// specified the `proxy` setting. Finally, we let you override it if you
|
|
||||||
// really know what you're doing with a special environment variable.
|
|
||||||
disableHostCheck:
|
|
||||||
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
|
|
||||||
// Enable gzip compression of generated files.
|
|
||||||
compress: true,
|
|
||||||
// Silence WebpackDevServer's own logs since they're generally not useful.
|
|
||||||
// It will still show compile warnings and errors with this setting.
|
|
||||||
clientLogLevel: 'none',
|
|
||||||
// By default WebpackDevServer serves physical files from current directory
|
|
||||||
// in addition to all the virtual build products that it serves from memory.
|
|
||||||
// This is confusing because those files won’t automatically be available in
|
|
||||||
// production build folder unless we copy them. However, copying the whole
|
|
||||||
// project directory is dangerous because we may expose sensitive files.
|
|
||||||
// Instead, we establish a convention that only files in `public` directory
|
|
||||||
// get served. Our build script will copy `public` into the `build` folder.
|
|
||||||
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
|
|
||||||
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
|
||||||
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
|
|
||||||
// Note that we only recommend to use `public` folder as an escape hatch
|
|
||||||
// for files like `favicon.ico`, `manifest.json`, and libraries that are
|
|
||||||
// for some reason broken when imported through webpack. If you just want to
|
|
||||||
// use an image, put it in `src` and `import` it from JavaScript instead.
|
|
||||||
contentBase: paths.appPublic,
|
|
||||||
contentBasePublicPath: paths.publicUrlOrPath,
|
|
||||||
// By default files from `contentBase` will not trigger a page reload.
|
|
||||||
watchContentBase: true,
|
|
||||||
// Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint
|
|
||||||
// for the WebpackDevServer client so it can learn when the files were
|
|
||||||
// updated. The WebpackDevServer client is included as an entry point
|
|
||||||
// in the webpack development configuration. Note that only changes
|
|
||||||
// to CSS are currently hot reloaded. JS changes will refresh the browser.
|
|
||||||
hot: true,
|
|
||||||
// Use 'ws' instead of 'sockjs-node' on server since we're using native
|
|
||||||
// websockets in `webpackHotDevClient`.
|
|
||||||
transportMode: 'ws',
|
|
||||||
// Prevent a WS client from getting injected as we're already including
|
|
||||||
// `webpackHotDevClient`.
|
|
||||||
injectClient: false,
|
|
||||||
// Enable custom sockjs pathname for websocket connection to hot reloading server.
|
|
||||||
// Enable custom sockjs hostname, pathname and port for websocket connection
|
|
||||||
// to hot reloading server.
|
|
||||||
sockHost,
|
|
||||||
sockPath,
|
|
||||||
sockPort,
|
|
||||||
// It is important to tell WebpackDevServer to use the same "publicPath" path as
|
|
||||||
// we specified in the webpack config. When homepage is '.', default to serving
|
|
||||||
// from the root.
|
|
||||||
// remove last slash so user can land on `/test` instead of `/test/`
|
|
||||||
publicPath: paths.publicUrlOrPath.slice(0, -1),
|
|
||||||
// WebpackDevServer is noisy by default so we emit custom message instead
|
|
||||||
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
|
|
||||||
quiet: true,
|
|
||||||
// Reportedly, this avoids CPU overload on some systems.
|
|
||||||
// https://github.com/facebook/create-react-app/issues/293
|
|
||||||
// src/node_modules is not ignored to support absolute imports
|
|
||||||
// https://github.com/facebook/create-react-app/issues/1065
|
|
||||||
watchOptions: {
|
|
||||||
ignored: ignoredFiles(paths.appSrc),
|
|
||||||
},
|
|
||||||
https: getHttpsConfig(),
|
|
||||||
host,
|
|
||||||
overlay: false,
|
|
||||||
historyApiFallback: {
|
|
||||||
// Paths with dots should still use the history fallback.
|
|
||||||
// See https://github.com/facebook/create-react-app/issues/387.
|
|
||||||
disableDotRule: true,
|
|
||||||
index: paths.publicUrlOrPath,
|
|
||||||
},
|
|
||||||
public: allowedHost,
|
|
||||||
// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
|
|
||||||
proxy,
|
|
||||||
before(app, server) {
|
|
||||||
// Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware`
|
|
||||||
// middlewares before `redirectServedPath` otherwise will not have any effect
|
|
||||||
// This lets us fetch source contents from webpack for the error overlay
|
|
||||||
app.use(evalSourceMapMiddleware(server));
|
|
||||||
// This lets us open files from the runtime error overlay.
|
|
||||||
app.use(errorOverlayMiddleware());
|
|
||||||
|
|
||||||
if (fs.existsSync(paths.proxySetup)) {
|
|
||||||
// This registers user provided middleware for proxy reasons
|
|
||||||
require(paths.proxySetup)(app);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
after(app) {
|
|
||||||
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
|
|
||||||
app.use(redirectServedPath(paths.publicUrlOrPath));
|
|
||||||
|
|
||||||
// This service worker file is effectively a 'no-op' that will reset any
|
|
||||||
// previous service worker registered for the same host:port combination.
|
|
||||||
// We do this in development to avoid hitting the production cache if
|
|
||||||
// it used the same host and port.
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
|
|
||||||
app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
120
package.json
120
package.json
@@ -3,12 +3,63 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"description": "AOE Technology Radar",
|
"description": "AOE Technology Radar",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"author": "AOE GmbH <contact-de@aoe.com> (http://www.aoe.com)",
|
||||||
"build": "tsc"
|
"license": "Apache-2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/AOEpeople/aoe_technology_radar.git"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"aoe_technology_radar": "scripts/build.js",
|
"generateJson": "scripts/generateJson.js",
|
||||||
"aoe_technology_radar-static": "bin/tasks/create-static.js"
|
"buildRadar": "scripts/buildRadar.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "react-scripts start",
|
||||||
|
"build": "react-scripts build",
|
||||||
|
"build:tasks": "tsc --project tsconfig.tasks.json",
|
||||||
|
"test": "react-scripts test",
|
||||||
|
"ts:check": "tsc --noEmit",
|
||||||
|
"lint": "yarn ts:check",
|
||||||
|
"prepare": "husky install",
|
||||||
|
"eject": "react-scripts eject"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"classnames": "^2.3.1",
|
||||||
|
"moment": "^2.29.1",
|
||||||
|
"query-string": "^7.0.0",
|
||||||
|
"react": "^17.0.2",
|
||||||
|
"react-dom": "^17.0.2",
|
||||||
|
"react-router-dom": "^5.2.0",
|
||||||
|
"react-scripts": "4.0.3",
|
||||||
|
"sass": "^1.34.0",
|
||||||
|
"typescript": "^4.1.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
|
"@testing-library/react": "^11.1.0",
|
||||||
|
"@testing-library/user-event": "^12.1.10",
|
||||||
|
"@types/fs-extra": "^9.0.11",
|
||||||
|
"@types/jest": "^26.0.15",
|
||||||
|
"@types/marked": "^2.0.3",
|
||||||
|
"@types/node": "^12.0.0",
|
||||||
|
"@types/react": "^17.0.0",
|
||||||
|
"@types/react-dom": "^17.0.0",
|
||||||
|
"@types/react-router-dom": "^5.1.7",
|
||||||
|
"@types/walk": "^2.3.0",
|
||||||
|
"front-matter": "^4.0.2",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
|
"highlight.js": "^11.0.0",
|
||||||
|
"husky": "^6.0.0",
|
||||||
|
"lint-staged": "^11.0.0",
|
||||||
|
"marked": "^2.0.7",
|
||||||
|
"prettier": "^2.3.0",
|
||||||
|
"walk": "^2.3.14"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"react-app",
|
||||||
|
"react-app/jest"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
@@ -21,66 +72,5 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"author": "AOE GmbH <contact-de@aoe.com> (http://www.aoe.com)",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/core": "7.9.0",
|
|
||||||
"@types/classnames": "^2.2.10",
|
|
||||||
"@types/fs-extra": "^9.0.1",
|
|
||||||
"@types/highlight.js": "^9.12.4",
|
|
||||||
"@types/marked": "^1.1.0",
|
|
||||||
"@types/node": "^12.0.0",
|
|
||||||
"@types/react": "^16.9.0",
|
|
||||||
"@types/react-router-dom": "^5.1.5",
|
|
||||||
"@types/walk": "^2.3.0",
|
|
||||||
"babel-loader": "8.1.0",
|
|
||||||
"babel-plugin-named-asset-import": "^0.3.6",
|
|
||||||
"babel-preset-react-app": "^9.1.2",
|
|
||||||
"camelcase": "^5.3.1",
|
|
||||||
"case-sensitive-paths-webpack-plugin": "2.3.0",
|
|
||||||
"classnames": "^2.2.6",
|
|
||||||
"css-loader": "3.4.2",
|
|
||||||
"dotenv": "8.2.0",
|
|
||||||
"dotenv-expand": "5.1.0",
|
|
||||||
"file-loader": "4.3.0",
|
|
||||||
"front-matter": "2.3.0",
|
|
||||||
"fs-extra": "^8.1.0",
|
|
||||||
"highlight.js": "10.5.0",
|
|
||||||
"html-webpack-plugin": "4.0.0-beta.11",
|
|
||||||
"jest": "^26.6.3",
|
|
||||||
"marked": "0.3.18",
|
|
||||||
"mini-css-extract-plugin": "0.9.0",
|
|
||||||
"moment": "2.22.1",
|
|
||||||
"node-sass": "4",
|
|
||||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
|
||||||
"pnp-webpack-plugin": "1.6.4",
|
|
||||||
"postcss-flexbugs-fixes": "4.1.0",
|
|
||||||
"postcss-loader": "3.0.0",
|
|
||||||
"postcss-normalize": "8.0.1",
|
|
||||||
"postcss-preset-env": "6.7.0",
|
|
||||||
"postcss-safe-parser": "4.0.1",
|
|
||||||
"query-string": "^6.13.1",
|
|
||||||
"react": "^16.13.1",
|
|
||||||
"react-dev-utils": "^10.2.1",
|
|
||||||
"react-dom": "^16.0.0",
|
|
||||||
"react-router-dom": "^5.2.0",
|
|
||||||
"resolve": "1.15.0",
|
|
||||||
"resolve-url-loader": "3.1.2",
|
|
||||||
"sass-loader": "8.0.2",
|
|
||||||
"style-loader": "0.23.1",
|
|
||||||
"terser-webpack-plugin": "2.3.8",
|
|
||||||
"ts-pnp": "1.1.6",
|
|
||||||
"typescript": "^3.9.6",
|
|
||||||
"url-loader": "2.3.0",
|
|
||||||
"walk": "2.3.9",
|
|
||||||
"webpack": "4.42.0",
|
|
||||||
"webpack-dev-server": "3.11.1",
|
|
||||||
"webpack-manifest-plugin": "2.2.0",
|
|
||||||
"workbox-webpack-plugin": "4.3.1"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/AOEpeople/aoe_technology_radar.git"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
215
scripts/build.js
215
scripts/build.js
@@ -1,215 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// Do this as the first thing so that any code reading it knows the right env.
|
|
||||||
process.env.BABEL_ENV = 'production';
|
|
||||||
process.env.NODE_ENV = 'production';
|
|
||||||
|
|
||||||
// Makes the script crash on unhandled rejections instead of silently
|
|
||||||
// ignoring them. In the future, promise rejections that are not handled will
|
|
||||||
// terminate the Node.js process with a non-zero exit code.
|
|
||||||
process.on('unhandledRejection', err => {
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure environment variables are read.
|
|
||||||
require('../config/env');
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const chalk = require('react-dev-utils/chalk');
|
|
||||||
const fs = require('fs-extra');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const configFactory = require('../config/webpack.config');
|
|
||||||
const paths = require('../config/paths');
|
|
||||||
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
|
||||||
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
|
|
||||||
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
|
|
||||||
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
|
|
||||||
const printBuildError = require('react-dev-utils/printBuildError');
|
|
||||||
|
|
||||||
const measureFileSizesBeforeBuild =
|
|
||||||
FileSizeReporter.measureFileSizesBeforeBuild;
|
|
||||||
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
|
|
||||||
const useYarn = fs.existsSync(paths.yarnLockFile);
|
|
||||||
|
|
||||||
// These sizes are pretty large. We'll warn for bundles exceeding them.
|
|
||||||
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
|
|
||||||
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
|
|
||||||
|
|
||||||
const isInteractive = process.stdout.isTTY;
|
|
||||||
|
|
||||||
// Warn and crash if required files are missing
|
|
||||||
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate configuration
|
|
||||||
const config = configFactory('production');
|
|
||||||
|
|
||||||
// We require that you explicitly set browsers and do not fall back to
|
|
||||||
// browserslist defaults.
|
|
||||||
const {checkBrowsers} = require('react-dev-utils/browsersHelper');
|
|
||||||
require('../bin/tasks/radarjson').radarJsonGenerator()
|
|
||||||
.then(checkBrowsers(paths.appPath, isInteractive))
|
|
||||||
.then(() => {
|
|
||||||
// First, read the current file sizes in build directory.
|
|
||||||
// This lets us display how much they changed later.
|
|
||||||
return measureFileSizesBeforeBuild(paths.appBuild);
|
|
||||||
})
|
|
||||||
.then(previousFileSizes => {
|
|
||||||
// Remove all content but keep the directory so that
|
|
||||||
// if you're in it, you don't end up in Trash
|
|
||||||
fs.emptyDirSync(paths.appBuild);
|
|
||||||
// Merge with the public folder
|
|
||||||
copyPublicFolder();
|
|
||||||
// Start the webpack build
|
|
||||||
return build(previousFileSizes);
|
|
||||||
})
|
|
||||||
.then(
|
|
||||||
({stats, previousFileSizes, warnings}) => {
|
|
||||||
if (warnings.length) {
|
|
||||||
console.log(chalk.yellow('Compiled with warnings.\n'));
|
|
||||||
console.log(warnings.join('\n\n'));
|
|
||||||
console.log(
|
|
||||||
'\nSearch for the ' +
|
|
||||||
chalk.underline(chalk.yellow('keywords')) +
|
|
||||||
' to learn more about each warning.'
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
'To ignore, add ' +
|
|
||||||
chalk.cyan('// eslint-disable-next-line') +
|
|
||||||
' to the line before.\n'
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log(chalk.green('Compiled successfully.\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('File sizes after gzip:\n');
|
|
||||||
printFileSizesAfterBuild(
|
|
||||||
stats,
|
|
||||||
previousFileSizes,
|
|
||||||
paths.appBuild,
|
|
||||||
WARN_AFTER_BUNDLE_GZIP_SIZE,
|
|
||||||
WARN_AFTER_CHUNK_GZIP_SIZE
|
|
||||||
);
|
|
||||||
console.log();
|
|
||||||
|
|
||||||
const appPackage = require(paths.appPackageJson);
|
|
||||||
const publicUrl = paths.publicUrlOrPath;
|
|
||||||
const publicPath = config.output.publicPath;
|
|
||||||
const buildFolder = path.relative(process.cwd(), paths.appBuild);
|
|
||||||
printHostingInstructions(
|
|
||||||
appPackage,
|
|
||||||
publicUrl,
|
|
||||||
publicPath,
|
|
||||||
buildFolder,
|
|
||||||
useYarn
|
|
||||||
);
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
|
||||||
if (tscCompileOnError) {
|
|
||||||
console.log(
|
|
||||||
chalk.yellow(
|
|
||||||
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
printBuildError(err);
|
|
||||||
} else {
|
|
||||||
console.log(chalk.red('Failed to compile.\n'));
|
|
||||||
printBuildError(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.catch(err => {
|
|
||||||
if (err && err.message) {
|
|
||||||
console.log(err.message);
|
|
||||||
}
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Create the production build and print the deployment instructions.
|
|
||||||
function build(previousFileSizes) {
|
|
||||||
// We used to support resolving modules according to `NODE_PATH`.
|
|
||||||
// This now has been deprecated in favor of jsconfig/tsconfig.json
|
|
||||||
// This lets you use absolute paths in imports inside large monorepos:
|
|
||||||
if (process.env.NODE_PATH) {
|
|
||||||
console.log(
|
|
||||||
chalk.yellow(
|
|
||||||
'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Creating an optimized production build...');
|
|
||||||
|
|
||||||
const compiler = webpack(config);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
compiler.run((err, stats) => {
|
|
||||||
let messages;
|
|
||||||
if (err) {
|
|
||||||
if (!err.message) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
let errMessage = err.message;
|
|
||||||
|
|
||||||
// Add additional information for postcss errors
|
|
||||||
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
|
|
||||||
errMessage +=
|
|
||||||
'\nCompileError: Begins at CSS selector ' +
|
|
||||||
err['postcssNode'].selector;
|
|
||||||
}
|
|
||||||
|
|
||||||
messages = formatWebpackMessages({
|
|
||||||
errors: [errMessage],
|
|
||||||
warnings: [],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
messages = formatWebpackMessages(
|
|
||||||
stats.toJson({all: false, warnings: true, errors: true})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (messages.errors.length) {
|
|
||||||
// Only keep the first error. Others are often indicative
|
|
||||||
// of the same problem, but confuse the reader with noise.
|
|
||||||
if (messages.errors.length > 1) {
|
|
||||||
messages.errors.length = 1;
|
|
||||||
}
|
|
||||||
return reject(new Error(messages.errors.join('\n\n')));
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
process.env.CI &&
|
|
||||||
(typeof process.env.CI !== 'string' ||
|
|
||||||
process.env.CI.toLowerCase() !== 'false') &&
|
|
||||||
messages.warnings.length
|
|
||||||
) {
|
|
||||||
console.log(
|
|
||||||
chalk.yellow(
|
|
||||||
'\nTreating warnings as errors because process.env.CI = true.\n' +
|
|
||||||
'Most CI servers set it automatically.\n'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return reject(new Error(messages.warnings.join('\n\n')));
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolve({
|
|
||||||
stats,
|
|
||||||
previousFileSizes,
|
|
||||||
warnings: messages.warnings,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyPublicFolder() {
|
|
||||||
fs.copySync(paths.appPublic, paths.appBuild, {
|
|
||||||
dereference: true,
|
|
||||||
filter: file => file !== paths.appHtml,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
53
scripts/buildRadar.js
Normal file
53
scripts/buildRadar.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = "production";
|
||||||
|
process.env.NODE_ENV = "production";
|
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on("unhandledRejection", (err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
const fs = require("fs-extra");
|
||||||
|
|
||||||
|
const runCommand = (command, args) => {
|
||||||
|
const cp = require("child_process");
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const executedCommand = cp.spawn(command, args, {
|
||||||
|
stdio: "inherit",
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
executedCommand.on("error", (error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
executedCommand.on("exit", (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Check if rd.json was created
|
||||||
|
// TODO: Check how to empty folders without interfere with generateJson job
|
||||||
|
// TODO: add dist folder for precompiled builder
|
||||||
|
|
||||||
|
process.chdir("node_modules/aoe_technology_radar");
|
||||||
|
fs.emptyDirSync("build");
|
||||||
|
runCommand("yarn build")
|
||||||
|
.then(() => {
|
||||||
|
fs.copySync("build", "../../build");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
28
scripts/generateJson.js
Normal file
28
scripts/generateJson.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = "production";
|
||||||
|
process.env.NODE_ENV = "production";
|
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on("unhandledRejection", (err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: execute yarn build:tasks to create bin folder with compiled radarJsonGenerator
|
||||||
|
|
||||||
|
require("../bin/tasks/radarjson")
|
||||||
|
.radarJsonGenerator()
|
||||||
|
.then(() => {
|
||||||
|
console.log("rd.json created");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (err && err.message) {
|
||||||
|
console.error(err.message);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
168
scripts/start.js
168
scripts/start.js
@@ -1,168 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// Do this as the first thing so that any code reading it knows the right env.
|
|
||||||
process.env.BABEL_ENV = 'development';
|
|
||||||
process.env.NODE_ENV = 'development';
|
|
||||||
|
|
||||||
// Makes the script crash on unhandled rejections instead of silently
|
|
||||||
// ignoring them. In the future, promise rejections that are not handled will
|
|
||||||
// terminate the Node.js process with a non-zero exit code.
|
|
||||||
process.on('unhandledRejection', err => {
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure environment variables are read.
|
|
||||||
require('../config/env');
|
|
||||||
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const chalk = require('react-dev-utils/chalk');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const WebpackDevServer = require('webpack-dev-server');
|
|
||||||
const clearConsole = require('react-dev-utils/clearConsole');
|
|
||||||
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
|
||||||
const {
|
|
||||||
choosePort,
|
|
||||||
createCompiler,
|
|
||||||
prepareProxy,
|
|
||||||
prepareUrls,
|
|
||||||
} = require('react-dev-utils/WebpackDevServerUtils');
|
|
||||||
const openBrowser = require('react-dev-utils/openBrowser');
|
|
||||||
const paths = require('../config/paths');
|
|
||||||
const configFactory = require('../config/webpack.config');
|
|
||||||
const createDevServerConfig = require('../config/webpackDevServer.config');
|
|
||||||
|
|
||||||
const useYarn = fs.existsSync(paths.yarnLockFile);
|
|
||||||
const isInteractive = process.stdout.isTTY;
|
|
||||||
|
|
||||||
// Warn and crash if required files are missing
|
|
||||||
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tools like Cloud9 rely on this.
|
|
||||||
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
|
|
||||||
const HOST = process.env.HOST || '0.0.0.0';
|
|
||||||
|
|
||||||
if (process.env.HOST) {
|
|
||||||
console.log(
|
|
||||||
chalk.cyan(
|
|
||||||
`Attempting to bind to HOST environment variable: ${chalk.yellow(
|
|
||||||
chalk.bold(process.env.HOST)
|
|
||||||
)}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`Learn more here: ${chalk.yellow('https://bit.ly/CRA-advanced-config')}`
|
|
||||||
);
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We require that you explicitly set browsers and do not fall back to
|
|
||||||
// browserslist defaults.
|
|
||||||
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
|
||||||
checkBrowsers(paths.appPath, isInteractive)
|
|
||||||
.then(() => {
|
|
||||||
// We attempt to use the default port but if it is busy, we offer the user to
|
|
||||||
// run on a different port. `choosePort()` Promise resolves to the next free port.
|
|
||||||
return choosePort(HOST, DEFAULT_PORT);
|
|
||||||
})
|
|
||||||
.then(port => {
|
|
||||||
if (port == null) {
|
|
||||||
// We have not found a port.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = configFactory('development');
|
|
||||||
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
|
||||||
const appName = require(paths.appPackageJson).name;
|
|
||||||
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
|
||||||
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
|
||||||
const urls = prepareUrls(
|
|
||||||
protocol,
|
|
||||||
HOST,
|
|
||||||
port,
|
|
||||||
paths.publicUrlOrPath.slice(0, -1)
|
|
||||||
);
|
|
||||||
const devSocket = {
|
|
||||||
warnings: warnings =>
|
|
||||||
devServer.sockWrite(devServer.sockets, 'warnings', warnings),
|
|
||||||
errors: errors =>
|
|
||||||
devServer.sockWrite(devServer.sockets, 'errors', errors),
|
|
||||||
};
|
|
||||||
// Create a webpack compiler that is configured with custom messages.
|
|
||||||
const compiler = createCompiler({
|
|
||||||
appName,
|
|
||||||
config,
|
|
||||||
devSocket,
|
|
||||||
urls,
|
|
||||||
useYarn,
|
|
||||||
useTypeScript,
|
|
||||||
tscCompileOnError,
|
|
||||||
webpack,
|
|
||||||
});
|
|
||||||
// Load proxy config
|
|
||||||
const proxySetting = require(paths.appPackageJson).proxy;
|
|
||||||
const proxyConfig = prepareProxy(
|
|
||||||
proxySetting,
|
|
||||||
paths.appPublic,
|
|
||||||
paths.publicUrlOrPath
|
|
||||||
);
|
|
||||||
// Serve webpack assets generated by the compiler over a web server.
|
|
||||||
const serverConfig = createDevServerConfig(
|
|
||||||
proxyConfig,
|
|
||||||
urls.lanUrlForConfig
|
|
||||||
);
|
|
||||||
const devServer = new WebpackDevServer(compiler, serverConfig);
|
|
||||||
// Launch WebpackDevServer.
|
|
||||||
devServer.listen(port, HOST, err => {
|
|
||||||
if (err) {
|
|
||||||
return console.log(err);
|
|
||||||
}
|
|
||||||
if (isInteractive) {
|
|
||||||
clearConsole();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We used to support resolving modules according to `NODE_PATH`.
|
|
||||||
// This now has been deprecated in favor of jsconfig/tsconfig.json
|
|
||||||
// This lets you use absolute paths in imports inside large monorepos:
|
|
||||||
if (process.env.NODE_PATH) {
|
|
||||||
console.log(
|
|
||||||
chalk.yellow(
|
|
||||||
'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(chalk.cyan('Starting the development server...\n'));
|
|
||||||
openBrowser(urls.localUrlForBrowser);
|
|
||||||
});
|
|
||||||
|
|
||||||
['SIGINT', 'SIGTERM'].forEach(function(sig) {
|
|
||||||
process.on(sig, function() {
|
|
||||||
devServer.close();
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isInteractive || process.env.CI !== 'true') {
|
|
||||||
// Gracefully exit when stdin ends
|
|
||||||
process.stdin.on('end', function() {
|
|
||||||
devServer.close();
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
process.stdin.resume();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
if (err && err.message) {
|
|
||||||
console.log(err.message);
|
|
||||||
}
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
// Do this as the first thing so that any code reading it knows the right env.
|
|
||||||
process.env.BABEL_ENV = 'test';
|
|
||||||
process.env.NODE_ENV = 'test';
|
|
||||||
process.env.PUBLIC_URL = '';
|
|
||||||
|
|
||||||
// Makes the script crash on unhandled rejections instead of silently
|
|
||||||
// ignoring them. In the future, promise rejections that are not handled will
|
|
||||||
// terminate the Node.js process with a non-zero exit code.
|
|
||||||
process.on('unhandledRejection', err => {
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure environment variables are read.
|
|
||||||
require('../config/env');
|
|
||||||
|
|
||||||
|
|
||||||
const jest = require('jest');
|
|
||||||
const execSync = require('child_process').execSync;
|
|
||||||
let argv = process.argv.slice(2);
|
|
||||||
|
|
||||||
function isInGitRepository() {
|
|
||||||
try {
|
|
||||||
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isInMercurialRepository() {
|
|
||||||
try {
|
|
||||||
execSync('hg --cwd . root', { stdio: 'ignore' });
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch unless on CI or explicitly running all tests
|
|
||||||
if (
|
|
||||||
!process.env.CI &&
|
|
||||||
argv.indexOf('--watchAll') === -1 &&
|
|
||||||
argv.indexOf('--watchAll=false') === -1
|
|
||||||
) {
|
|
||||||
// https://github.com/facebook/create-react-app/issues/5210
|
|
||||||
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
|
|
||||||
argv.push(hasSourceControl ? '--watch' : '--watchAll');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
jest.run(argv);
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
// Add Google Analytics
|
|
||||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
|
||||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
|
||||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
|
||||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
|
||||||
|
|
||||||
ga('create', 'UA-839059-1', 'auto');
|
|
||||||
|
|
||||||
export function track() {
|
|
||||||
ga('set', 'location', document.location.href);
|
|
||||||
ga('send', 'pageview');
|
|
||||||
}
|
|
||||||
@@ -1,57 +1,103 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import classNames from 'classnames';
|
import classNames from "classnames";
|
||||||
import Header from './Header/Header';
|
import Header from "./Header/Header";
|
||||||
import Footer from './Footer/Footer';
|
import Footer from "./Footer/Footer";
|
||||||
import Router from './Router';
|
import Router from "./Router";
|
||||||
import {BrowserRouter, Switch, Route, Redirect, useParams, useLocation} from 'react-router-dom';
|
import {
|
||||||
import {Item} from '../model';
|
BrowserRouter,
|
||||||
|
Switch,
|
||||||
|
Route,
|
||||||
|
Redirect,
|
||||||
|
useParams,
|
||||||
|
useLocation,
|
||||||
|
} from "react-router-dom";
|
||||||
|
import { Item } from "../model";
|
||||||
|
|
||||||
|
interface Params {
|
||||||
|
page: string;
|
||||||
|
}
|
||||||
|
|
||||||
const useQuery = () => {
|
const useQuery = () => {
|
||||||
return new URLSearchParams(useLocation().search);
|
return new URLSearchParams(useLocation().search);
|
||||||
}
|
};
|
||||||
|
|
||||||
const RouterWithPageParam = ({items, releases}: { items: Item[], releases: string[] }) => {
|
const RouterWithPageParam = ({
|
||||||
const {page} = useParams();
|
items,
|
||||||
|
releases,
|
||||||
|
}: {
|
||||||
|
items: Item[];
|
||||||
|
releases: string[];
|
||||||
|
}) => {
|
||||||
|
const { page } = useParams<Params>();
|
||||||
const query = useQuery();
|
const query = useQuery();
|
||||||
|
|
||||||
return <Router pageName={page} search={query.get('search') || ''} items={items} releases={releases}/>;
|
return (
|
||||||
|
<Router
|
||||||
|
pageName={page}
|
||||||
|
search={query.get("search") || ""}
|
||||||
|
items={items}
|
||||||
|
releases={releases}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const HeaderWithPageParam = () => {
|
const HeaderWithPageParam = () => {
|
||||||
const {page} = useParams();
|
const { page } = useParams<Params>();
|
||||||
|
|
||||||
return <Header pageName={page}/>
|
return <Header pageName={page} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FooterWithPageParam = ({ items }: { items: Item[] }) => {
|
const FooterWithPageParam = ({ items }: { items: Item[] }) => {
|
||||||
const {page} = useParams();
|
const { page } = useParams<Params>();
|
||||||
|
|
||||||
return <Footer pageName={page} items={items}/>
|
return <Footer pageName={page} items={items} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function App({items, releases}: { items: Item[], releases: string[] }) {
|
interface Data {
|
||||||
|
items: Item[];
|
||||||
|
releases: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const [data, setData] = React.useState<Data>();
|
||||||
|
React.useEffect(() => {
|
||||||
|
fetch("rd.json")
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data: Data) => {
|
||||||
|
setData(data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("fetch data", error);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
const { items, releases } = data;
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path={'/techradar/:page(.+).html'}>
|
<Route path={"/techradar/:page(.+).html"}>
|
||||||
<div>
|
<div>
|
||||||
<div className='page'>
|
<div className="page">
|
||||||
<div className='page__header'>
|
<div className="page__header">
|
||||||
<HeaderWithPageParam />
|
<HeaderWithPageParam />
|
||||||
</div>
|
</div>
|
||||||
<div className={classNames('page__content')}>
|
<div className={classNames("page__content")}>
|
||||||
<RouterWithPageParam items={items} releases={releases} />
|
<RouterWithPageParam items={items} releases={releases} />
|
||||||
</div>
|
</div>
|
||||||
<div className='page__footer'>
|
<div className="page__footer">
|
||||||
<FooterWithPageParam items={items} />
|
<FooterWithPageParam items={items} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Route>
|
</Route>
|
||||||
<Route path={'/'}>
|
<Route path={"/"}>
|
||||||
<Redirect to={'/techradar/index.html'}/>
|
<Redirect to={"/techradar/index.html"} />
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import './flag.scss';
|
import "./flag.scss";
|
||||||
import {FlagType} from "../../model";
|
|
||||||
|
export type FlagType = "new" | "changed" | "default";
|
||||||
|
|
||||||
interface ItemFlag {
|
interface ItemFlag {
|
||||||
flag: FlagType;
|
flag: FlagType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Flag({ item, short = false }: { item: ItemFlag; short?: boolean }) {
|
export default function Flag({
|
||||||
|
item,
|
||||||
|
short = false,
|
||||||
|
}: {
|
||||||
|
item: ItemFlag;
|
||||||
|
short?: boolean;
|
||||||
|
}) {
|
||||||
const ucFirst = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
|
const ucFirst = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
|
||||||
|
|
||||||
if (item.flag !== 'default') {
|
if (item.flag !== "default") {
|
||||||
let name = item.flag.toUpperCase();
|
let name = item.flag.toUpperCase();
|
||||||
let title = ucFirst(item.flag);
|
let title = ucFirst(item.flag);
|
||||||
if (short === true) {
|
if (short === true) {
|
||||||
|
|||||||
35
src/config.js
Normal file
35
src/config.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
export var radarName = process.env.RADAR_NAME || 'AOE Technology Radar';
|
||||||
|
export var radarNameShort = radarName;
|
||||||
|
export var quadrants = [
|
||||||
|
'languages-and-frameworks',
|
||||||
|
'methods-and-patterns',
|
||||||
|
'platforms-and-aoe-services',
|
||||||
|
'tools',
|
||||||
|
];
|
||||||
|
export var rings = [
|
||||||
|
'all',
|
||||||
|
'adopt',
|
||||||
|
'trial',
|
||||||
|
'assess',
|
||||||
|
'hold'
|
||||||
|
];
|
||||||
|
export var getItemPageNames = function (items) { return items.map(function (item) { return item.quadrant + "/" + item.name; }); };
|
||||||
|
export var showEmptyRings = false;
|
||||||
|
var messages = {
|
||||||
|
'languages-and-frameworks': 'Languages & Frameworks',
|
||||||
|
'methods-and-patterns': 'Methods & Patterns',
|
||||||
|
'platforms-and-aoe-services': 'Platforms and Operations',
|
||||||
|
'tools': 'Tools',
|
||||||
|
};
|
||||||
|
export var translate = function (key) { return (messages[key] || '-'); };
|
||||||
|
export function isMobileViewport() {
|
||||||
|
// return false for server side rendering
|
||||||
|
if (typeof window == 'undefined')
|
||||||
|
return false;
|
||||||
|
var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
|
return width < 1200;
|
||||||
|
}
|
||||||
|
export function assetUrl(file) {
|
||||||
|
return process.env.PUBLIC_URL + '/' + file;
|
||||||
|
// return `/techradar/assets/${file}`
|
||||||
|
}
|
||||||
13
src/index.css
Normal file
13
src/index.css
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
|
sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
@@ -58,4 +58,4 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@import './styles/main.scss'
|
@import './styles/main.scss';
|
||||||
11
src/index.tsx
Normal file
11
src/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import App from "./components/App";
|
||||||
|
import "./index.scss";
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>,
|
||||||
|
document.getElementById("root")
|
||||||
|
);
|
||||||
1
src/logo.svg
Normal file
1
src/logo.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 2.6 KiB |
49
src/model.js
Normal file
49
src/model.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
var __assign = (this && this.__assign) || function () {
|
||||||
|
__assign = Object.assign || function(t) {
|
||||||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
|
s = arguments[i];
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||||
|
t[p] = s[p];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
return __assign.apply(this, arguments);
|
||||||
|
};
|
||||||
|
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
||||||
|
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
|
||||||
|
to[j] = from[i];
|
||||||
|
return to;
|
||||||
|
};
|
||||||
|
export var featuredOnly = function (items) { return items.filter(function (item) { return item.featured; }); };
|
||||||
|
export var groupByQuadrants = function (items) {
|
||||||
|
return items.reduce(function (quadrants, item) {
|
||||||
|
var _a;
|
||||||
|
return (__assign(__assign({}, quadrants), (_a = {}, _a[item.quadrant] = addItemToQuadrant(quadrants[item.quadrant], item), _a)));
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
export var groupByFirstLetter = function (items) {
|
||||||
|
var index = items.reduce(function (letterIndex, item) {
|
||||||
|
var _a;
|
||||||
|
return (__assign(__assign({}, letterIndex), (_a = {}, _a[getFirstLetter(item)] = addItemToList(letterIndex[getFirstLetter(item)], item), _a)));
|
||||||
|
}, {});
|
||||||
|
return Object.keys(index)
|
||||||
|
.sort()
|
||||||
|
.map(function (letter) { return ({
|
||||||
|
letter: letter,
|
||||||
|
items: index[letter],
|
||||||
|
}); });
|
||||||
|
};
|
||||||
|
var addItemToQuadrant = function (quadrant, item) {
|
||||||
|
var _a;
|
||||||
|
if (quadrant === void 0) { quadrant = {}; }
|
||||||
|
return (__assign(__assign({}, quadrant), (_a = {}, _a[item.ring] = addItemToRing(quadrant[item.ring], item), _a)));
|
||||||
|
};
|
||||||
|
var addItemToList = function (list, item) {
|
||||||
|
if (list === void 0) { list = []; }
|
||||||
|
return __spreadArray(__spreadArray([], list), [item]);
|
||||||
|
};
|
||||||
|
var addItemToRing = function (ring, item) {
|
||||||
|
if (ring === void 0) { ring = []; }
|
||||||
|
return __spreadArray(__spreadArray([], ring), [item]);
|
||||||
|
};
|
||||||
|
export var getFirstLetter = function (item) { return item.title.substr(0, 1).toUpperCase(); };
|
||||||
67
src/react-app-env.d.ts
vendored
67
src/react-app-env.d.ts
vendored
@@ -1,66 +1 @@
|
|||||||
/// <reference types="node" />
|
/// <reference types="react-scripts" />
|
||||||
/// <reference types="react" />
|
|
||||||
/// <reference types="react-dom" />
|
|
||||||
|
|
||||||
declare namespace NodeJS {
|
|
||||||
interface ProcessEnv {
|
|
||||||
readonly NODE_ENV: 'development' | 'production' | 'test';
|
|
||||||
readonly PUBLIC_URL: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.bmp' {
|
|
||||||
const src: string;
|
|
||||||
export default src;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.gif' {
|
|
||||||
const src: string;
|
|
||||||
export default src;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.jpg' {
|
|
||||||
const src: string;
|
|
||||||
export default src;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.jpeg' {
|
|
||||||
const src: string;
|
|
||||||
export default src;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.png' {
|
|
||||||
const src: string;
|
|
||||||
export default src;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.webp' {
|
|
||||||
const src: string;
|
|
||||||
export default src;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.svg' {
|
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
export const ReactComponent: React.FunctionComponent<React.SVGProps<
|
|
||||||
SVGSVGElement
|
|
||||||
> & { title?: string }>;
|
|
||||||
|
|
||||||
const src: string;
|
|
||||||
export default src;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.module.css' {
|
|
||||||
const classes: { readonly [key: string]: string };
|
|
||||||
export default classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.module.scss' {
|
|
||||||
const classes: { readonly [key: string]: string };
|
|
||||||
export default classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.module.sass' {
|
|
||||||
const classes: { readonly [key: string]: string };
|
|
||||||
export default classes;
|
|
||||||
}
|
|
||||||
|
|||||||
5
src/setupTests.ts
Normal file
5
src/setupTests.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||||
|
// allows you to do things like:
|
||||||
|
// expect(element).toHaveTextContent(/react/i)
|
||||||
|
// learn more: https://github.com/testing-library/jest-dom
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
69
tasks/create-static.js
Normal file
69
tasks/create-static.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (_) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
import { createRadar } from "./radar";
|
||||||
|
import { copyFileSync, mkdirSync } from "fs";
|
||||||
|
import { quadrants } from "../src/config";
|
||||||
|
(function () { return __awaiter(void 0, void 0, void 0, function () {
|
||||||
|
var radar, e_1;
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0:
|
||||||
|
_a.trys.push([0, 2, , 3]);
|
||||||
|
console.log('starting static');
|
||||||
|
return [4 /*yield*/, createRadar()];
|
||||||
|
case 1:
|
||||||
|
radar = _a.sent();
|
||||||
|
copyFileSync('build/index.html', 'build/overview.html');
|
||||||
|
copyFileSync('build/index.html', 'build/help-and-about-tech-radar.html');
|
||||||
|
quadrants.forEach(function (quadrant) {
|
||||||
|
copyFileSync('build/index.html', 'build/' + quadrant + '.html');
|
||||||
|
mkdirSync('build/' + quadrant);
|
||||||
|
});
|
||||||
|
radar.items.forEach(function (item) {
|
||||||
|
copyFileSync('build/index.html', 'build/' + item.quadrant + '/' + item.name + '.html');
|
||||||
|
});
|
||||||
|
console.log('created static');
|
||||||
|
return [3 /*break*/, 3];
|
||||||
|
case 2:
|
||||||
|
e_1 = _a.sent();
|
||||||
|
console.error('error:', e_1);
|
||||||
|
return [3 /*break*/, 3];
|
||||||
|
case 3: return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}); })();
|
||||||
86
tasks/file.js
Normal file
86
tasks/file.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
||||||
|
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
|
||||||
|
to[j] = from[i];
|
||||||
|
return to;
|
||||||
|
};
|
||||||
|
import { outputFile } from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import { walk } from 'walk';
|
||||||
|
export var relativePath = function () {
|
||||||
|
var relativePath = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
relativePath[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
// path.resolve(__dirname, '..', ...relativePath)
|
||||||
|
path.resolve.apply(
|
||||||
|
// path.resolve(__dirname, '..', ...relativePath)
|
||||||
|
path, relativePath));
|
||||||
|
};
|
||||||
|
export var radarPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return (relativePath.apply(void 0, __spreadArray(['radar'], pathInSrc)));
|
||||||
|
};
|
||||||
|
export var stylesPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return (relativePath.apply(void 0, __spreadArray(['styles'], pathInSrc)));
|
||||||
|
};
|
||||||
|
export var assetsPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return (relativePath.apply(void 0, __spreadArray(['assets'], pathInSrc)));
|
||||||
|
};
|
||||||
|
export var faviconPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return (relativePath.apply(void 0, __spreadArray(['assets/favicon.ico'], pathInSrc)));
|
||||||
|
};
|
||||||
|
export var jsPath = function () {
|
||||||
|
var pathInSrc = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInSrc[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return (relativePath.apply(void 0, __spreadArray(['js'], pathInSrc)));
|
||||||
|
};
|
||||||
|
export var distPath = function () {
|
||||||
|
var pathInDist = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
pathInDist[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
return (relativePath.apply(void 0, __spreadArray(['src'], pathInDist)));
|
||||||
|
};
|
||||||
|
export var getAllMarkdownFiles = function (folder) { return (getAllFiles(folder, isMarkdownFile)); };
|
||||||
|
var getAllFiles = function (folder, predicate) { return (new Promise(function (resolve, reject) {
|
||||||
|
var walker = walk(folder, { followLinks: false });
|
||||||
|
var files = [];
|
||||||
|
walker.on("file", function (root, fileStat, next) {
|
||||||
|
if (predicate(fileStat.name)) {
|
||||||
|
files.push(path.resolve(root, fileStat.name));
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
walker.on("errors", function (root, nodeStatsArray, next) {
|
||||||
|
nodeStatsArray.forEach(function (n) {
|
||||||
|
console.error("[ERROR] " + n.name);
|
||||||
|
if (n.error) {
|
||||||
|
console.error(n.error.message || (n.error.code + ": " + n.error.path));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
walker.on("end", function () {
|
||||||
|
resolve(files.sort());
|
||||||
|
});
|
||||||
|
})); };
|
||||||
|
var isMarkdownFile = function (name) { return name.match(/\.md$/) !== null; };
|
||||||
|
export var save = function (data, fileName) { return outputFile(distPath(fileName), data); };
|
||||||
@@ -1,41 +1,42 @@
|
|||||||
import { outputFile } from 'fs-extra';
|
import { outputFile } from "fs-extra";
|
||||||
import path from 'path';
|
import path from "path";
|
||||||
import { walk } from 'walk';
|
import { walk } from "walk";
|
||||||
|
|
||||||
export const relativePath = (...relativePath: string[]): string => (
|
export const relativePath = (...relativePath: string[]): string =>
|
||||||
// path.resolve(__dirname, '..', ...relativePath)
|
// path.resolve(__dirname, '..', ...relativePath)
|
||||||
path.resolve(...relativePath)
|
path.resolve(...relativePath);
|
||||||
);
|
|
||||||
|
|
||||||
export const radarPath = (...pathInSrc: string[]) => (
|
export const radarPath = (...pathInSrc: string[]) =>
|
||||||
relativePath('radar', ...pathInSrc)
|
relativePath("radar", ...pathInSrc);
|
||||||
);
|
|
||||||
|
|
||||||
export const stylesPath = (...pathInSrc: string[]) => (
|
export const stylesPath = (...pathInSrc: string[]) =>
|
||||||
relativePath('styles', ...pathInSrc)
|
relativePath("styles", ...pathInSrc);
|
||||||
);
|
|
||||||
|
|
||||||
export const assetsPath = (...pathInSrc: string[]) => (
|
export const assetsPath = (...pathInSrc: string[]) =>
|
||||||
relativePath('assets', ...pathInSrc)
|
relativePath("assets", ...pathInSrc);
|
||||||
);
|
|
||||||
|
|
||||||
export const faviconPath = (...pathInSrc: string[]) => (
|
export const faviconPath = (...pathInSrc: string[]) =>
|
||||||
relativePath('assets/favicon.ico', ...pathInSrc)
|
relativePath("assets/favicon.ico", ...pathInSrc);
|
||||||
);
|
|
||||||
|
|
||||||
export const jsPath = (...pathInSrc: string[]) => (
|
export const jsPath = (...pathInSrc: string[]) =>
|
||||||
relativePath('js', ...pathInSrc)
|
relativePath("js", ...pathInSrc);
|
||||||
);
|
|
||||||
|
|
||||||
export const distPath = (...pathInDist: string[]) => (
|
export const publicPath = (...pathInDist: string[]) =>
|
||||||
relativePath('src', ...pathInDist)
|
relativePath("public", ...pathInDist);
|
||||||
);
|
|
||||||
|
|
||||||
export const getAllMarkdownFiles = (folder: string) => (
|
export const buildPath = (...pathInDist: string[]) =>
|
||||||
getAllFiles(folder, isMarkdownFile)
|
relativePath("build", ...pathInDist);
|
||||||
);
|
|
||||||
|
|
||||||
const getAllFiles = (folder: string, predicate: (s: string) => boolean): Promise<string[]> => (
|
export const builderPath = (...pathInDist: string[]) =>
|
||||||
|
relativePath("node_modules", "aoe_technology_radar", "src", ...pathInDist);
|
||||||
|
|
||||||
|
export const getAllMarkdownFiles = (folder: string) =>
|
||||||
|
getAllFiles(folder, isMarkdownFile);
|
||||||
|
|
||||||
|
const getAllFiles = (
|
||||||
|
folder: string,
|
||||||
|
predicate: (s: string) => boolean
|
||||||
|
): Promise<string[]> =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
const walker = walk(folder, { followLinks: false });
|
const walker = walk(folder, { followLinks: false });
|
||||||
const files: string[] = [];
|
const files: string[] = [];
|
||||||
@@ -49,9 +50,9 @@ const getAllFiles = (folder: string, predicate: (s: string) => boolean): Promise
|
|||||||
|
|
||||||
walker.on("errors", (root, nodeStatsArray, next) => {
|
walker.on("errors", (root, nodeStatsArray, next) => {
|
||||||
nodeStatsArray.forEach(function (n) {
|
nodeStatsArray.forEach(function (n) {
|
||||||
console.error("[ERROR] " + n.name)
|
console.error("[ERROR] " + n.name);
|
||||||
if (n.error) {
|
if (n.error) {
|
||||||
console.error(n.error.message || (n.error.code + ": " + n.error.path));
|
console.error(n.error.message || n.error.code + ": " + n.error.path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
@@ -60,9 +61,9 @@ const getAllFiles = (folder: string, predicate: (s: string) => boolean): Promise
|
|||||||
walker.on("end", () => {
|
walker.on("end", () => {
|
||||||
resolve(files.sort());
|
resolve(files.sort());
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const isMarkdownFile = (name: string) => name.match(/\.md$/) !== null;
|
const isMarkdownFile = (name: string) => name.match(/\.md$/) !== null;
|
||||||
|
|
||||||
export const save = (data: string | Buffer | DataView, fileName: string) => outputFile(distPath(fileName), data);
|
export const save = (data: string | Buffer | DataView, fileName: string) =>
|
||||||
|
outputFile(buildPath(fileName), data);
|
||||||
|
|||||||
186
tasks/radar.js
Normal file
186
tasks/radar.js
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
var __assign = (this && this.__assign) || function () {
|
||||||
|
__assign = Object.assign || function(t) {
|
||||||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
|
s = arguments[i];
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||||
|
t[p] = s[p];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
return __assign.apply(this, arguments);
|
||||||
|
};
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (_) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
||||||
|
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
|
||||||
|
to[j] = from[i];
|
||||||
|
return to;
|
||||||
|
};
|
||||||
|
import { readFile } from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import frontmatter from 'front-matter';
|
||||||
|
import marked from 'marked';
|
||||||
|
import hljs from 'highlight.js';
|
||||||
|
import { quadrants, rings } from '../src/config';
|
||||||
|
import { radarPath, getAllMarkdownFiles } from './file';
|
||||||
|
marked.setOptions({
|
||||||
|
highlight: function (code) { return hljs.highlightAuto(code).value; },
|
||||||
|
});
|
||||||
|
export var createRadar = function () { return __awaiter(void 0, void 0, void 0, function () {
|
||||||
|
var fileNames, revisions, allReleases, items, flaggedItems;
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0: return [4 /*yield*/, getAllMarkdownFiles(radarPath())];
|
||||||
|
case 1:
|
||||||
|
fileNames = _a.sent();
|
||||||
|
return [4 /*yield*/, createRevisionsFromFiles(fileNames)];
|
||||||
|
case 2:
|
||||||
|
revisions = _a.sent();
|
||||||
|
allReleases = getAllReleases(revisions);
|
||||||
|
items = createItems(revisions);
|
||||||
|
flaggedItems = flagItem(items, allReleases);
|
||||||
|
return [2 /*return*/, {
|
||||||
|
items: flaggedItems,
|
||||||
|
releases: allReleases,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}); };
|
||||||
|
var checkAttributes = function (fileName, attributes) {
|
||||||
|
if (attributes.ring && !rings.includes(attributes.ring)) {
|
||||||
|
throw new Error("Error: " + fileName + " has an illegal value for 'ring' - must be one of " + rings);
|
||||||
|
}
|
||||||
|
if (attributes.quadrant && !quadrants.includes(attributes.quadrant)) {
|
||||||
|
throw new Error("Error: " + fileName + " has an illegal value for 'quadrant' - must be one of " + quadrants);
|
||||||
|
}
|
||||||
|
return attributes;
|
||||||
|
};
|
||||||
|
var createRevisionsFromFiles = function (fileNames) {
|
||||||
|
return Promise.all(fileNames.map(function (fileName) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
readFile(fileName, 'utf8', function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var fm = frontmatter(data);
|
||||||
|
// add target attribute to external links
|
||||||
|
// todo: check path
|
||||||
|
var html = marked(fm.body.replace(/\]\(\//g, '](/techradar/'));
|
||||||
|
html = html.replace(/a href="http/g, 'a target="_blank" rel="noopener noreferrer" href="http');
|
||||||
|
resolve(__assign(__assign(__assign({}, itemInfoFromFilename(fileName)), checkAttributes(fileName, fm.attributes)), { fileName: fileName, body: html }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
var itemInfoFromFilename = function (fileName) {
|
||||||
|
var _a = fileName.split(path.sep).slice(-2), release = _a[0], name = _a[1];
|
||||||
|
return {
|
||||||
|
name: path.basename(name, '.md'),
|
||||||
|
release: release,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var getAllReleases = function (revisions) {
|
||||||
|
return revisions
|
||||||
|
.reduce(function (allReleases, _a) {
|
||||||
|
var release = _a.release;
|
||||||
|
if (!allReleases.includes(release)) {
|
||||||
|
return __spreadArray(__spreadArray([], allReleases), [release]);
|
||||||
|
}
|
||||||
|
return allReleases;
|
||||||
|
}, [])
|
||||||
|
.sort();
|
||||||
|
};
|
||||||
|
var createItems = function (revisions) {
|
||||||
|
var itemMap = revisions.reduce(function (items, revision) {
|
||||||
|
var _a;
|
||||||
|
return __assign(__assign({}, items), (_a = {}, _a[revision.name] = addRevisionToItem(items[revision.name], revision), _a));
|
||||||
|
}, {});
|
||||||
|
return Object.values(itemMap).map(function (item) {
|
||||||
|
var _a;
|
||||||
|
return (__assign(__assign({}, item), (_a = {}, _a['title'] = item.title || item.name, _a)));
|
||||||
|
}).sort(function (x, y) { return (x.name > y.name ? 1 : -1); });
|
||||||
|
};
|
||||||
|
var ignoreEmptyRevisionBody = function (revision, item) {
|
||||||
|
if (!revision.body || revision.body.trim() === '') {
|
||||||
|
return item.body;
|
||||||
|
}
|
||||||
|
return revision.body;
|
||||||
|
};
|
||||||
|
var addRevisionToItem = function (item, revision) {
|
||||||
|
if (item === void 0) { item = {
|
||||||
|
flag: 'default',
|
||||||
|
featured: true,
|
||||||
|
revisions: [],
|
||||||
|
name: '',
|
||||||
|
title: '',
|
||||||
|
ring: 'trial',
|
||||||
|
quadrant: '',
|
||||||
|
body: '',
|
||||||
|
info: '',
|
||||||
|
}; }
|
||||||
|
var newItem = __assign(__assign(__assign({}, item), revision), { body: ignoreEmptyRevisionBody(revision, item) });
|
||||||
|
if (revisionCreatesNewHistoryEntry(revision)) {
|
||||||
|
newItem = __assign(__assign({}, newItem), { revisions: __spreadArray([revision], newItem.revisions) });
|
||||||
|
}
|
||||||
|
return newItem;
|
||||||
|
};
|
||||||
|
var revisionCreatesNewHistoryEntry = function (revision) {
|
||||||
|
return revision.body.trim() !== '' || typeof revision.ring !== 'undefined';
|
||||||
|
};
|
||||||
|
var flagItem = function (items, allReleases) {
|
||||||
|
return items.map(function (item) { return (__assign(__assign({}, item), { flag: getItemFlag(item, allReleases) })); }, []);
|
||||||
|
};
|
||||||
|
var isInLastRelease = function (item, allReleases) {
|
||||||
|
return item.revisions[0].release === allReleases[allReleases.length - 1];
|
||||||
|
};
|
||||||
|
var isNewItem = function (item, allReleases) {
|
||||||
|
return item.revisions.length === 1 && isInLastRelease(item, allReleases);
|
||||||
|
};
|
||||||
|
var hasItemChanged = function (item, allReleases) {
|
||||||
|
return item.revisions.length > 1 && isInLastRelease(item, allReleases);
|
||||||
|
};
|
||||||
|
var getItemFlag = function (item, allReleases) {
|
||||||
|
if (isNewItem(item, allReleases)) {
|
||||||
|
return 'new';
|
||||||
|
}
|
||||||
|
if (hasItemChanged(item, allReleases)) {
|
||||||
|
return 'changed';
|
||||||
|
}
|
||||||
|
return 'default';
|
||||||
|
};
|
||||||
61
tasks/radarjson.js
Normal file
61
tasks/radarjson.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||||
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||||
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||||
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||||
|
function step(op) {
|
||||||
|
if (f) throw new TypeError("Generator is already executing.");
|
||||||
|
while (_) try {
|
||||||
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||||
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||||
|
switch (op[0]) {
|
||||||
|
case 0: case 1: t = op; break;
|
||||||
|
case 4: _.label++; return { value: op[1], done: false };
|
||||||
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||||
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||||
|
default:
|
||||||
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||||
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||||
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||||
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||||
|
if (t[2]) _.ops.pop();
|
||||||
|
_.trys.pop(); continue;
|
||||||
|
}
|
||||||
|
op = body.call(thisArg, _);
|
||||||
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||||
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
import { createRadar } from "./radar";
|
||||||
|
import { save } from "./file";
|
||||||
|
export var radarJsonGenerator = function () { return __awaiter(void 0, void 0, void 0, function () {
|
||||||
|
var radar, e_1;
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0:
|
||||||
|
_a.trys.push([0, 2, , 3]);
|
||||||
|
console.log("start");
|
||||||
|
return [4 /*yield*/, createRadar()];
|
||||||
|
case 1:
|
||||||
|
radar = _a.sent();
|
||||||
|
save(JSON.stringify(radar), "rd.json");
|
||||||
|
save("import React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from 'aoe_technology_radar/src/components/App';\nimport 'aoe_technology_radar/src/index.scss';\nimport radardata from './rd.json';\n\nReactDOM.render(\n <React.StrictMode>\n <App items={radardata.items as Item[]} releases={radardata.releases as string[]} />\n </React.StrictMode>,\n document.getElementById('root')\n);\n", "index.tsx");
|
||||||
|
console.log("Built radar");
|
||||||
|
return [3 /*break*/, 3];
|
||||||
|
case 2:
|
||||||
|
e_1 = _a.sent();
|
||||||
|
console.error("error:", e_1);
|
||||||
|
return [3 /*break*/, 3];
|
||||||
|
case 3: return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}); };
|
||||||
@@ -2,35 +2,13 @@
|
|||||||
|
|
||||||
import { createRadar } from "./radar";
|
import { createRadar } from "./radar";
|
||||||
import { save } from "./file";
|
import { save } from "./file";
|
||||||
import {copyFileSync, mkdir, mkdirSync} from "fs";
|
|
||||||
import {quadrants} from "../src/config";
|
|
||||||
|
|
||||||
|
export const radarJsonGenerator = async () => {
|
||||||
export const radarJsonGenerator = (async () => {
|
|
||||||
try {
|
try {
|
||||||
console.log('start')
|
|
||||||
const radar = await createRadar();
|
const radar = await createRadar();
|
||||||
|
|
||||||
// console.log(radar);
|
await save(JSON.stringify(radar), "rd.json");
|
||||||
|
|
||||||
save(JSON.stringify(radar), 'rd.json')
|
|
||||||
save(`import React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import App from 'aoe_technology_radar/src/components/App';
|
|
||||||
import 'aoe_technology_radar/src/index.scss';
|
|
||||||
import {Item} from "aoe_technology_radar/src/model";
|
|
||||||
import radardata from './rd.json';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
|
||||||
<React.StrictMode>
|
|
||||||
<App items={radardata.items as Item[]} releases={radardata.releases as string[]} />
|
|
||||||
</React.StrictMode>,
|
|
||||||
document.getElementById('root')
|
|
||||||
);
|
|
||||||
`, 'index.tsx')
|
|
||||||
|
|
||||||
console.log('Built radar');
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('error:', e);
|
console.error("error:", e);
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
|
|||||||
@@ -1,26 +1,20 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2015",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": false,
|
"allowJs": false,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"module": "CommonJS",
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "react",
|
"noEmit": true,
|
||||||
"outDir": "bin",
|
"jsx": "react-jsx"
|
||||||
"resolveJsonModule": true
|
|
||||||
},
|
},
|
||||||
"files": [
|
"include": ["src"]
|
||||||
"tasks/radarjson.ts",
|
|
||||||
"tasks/create-static.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
21
tsconfig.tasks.json
Normal file
21
tsconfig.tasks.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"module": "CommonJS",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"outDir": "bin",
|
||||||
|
"noEmit": false
|
||||||
|
},
|
||||||
|
"files": ["tasks/radarjson.ts", "tasks/create-static.ts"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user