keycloakify 11.0.0 → 11.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -132,6 +132,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
132
132
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/oliviergoulet5"><img src="https://avatars.githubusercontent.com/u/17685861?v=4?s=100" width="100px;" alt="Olivier Goulet"/><br /><sub><b>Olivier Goulet</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=oliviergoulet5" title="Code">💻</a></td>
133
133
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/liamlows"><img src="https://avatars.githubusercontent.com/u/1365914?v=4?s=100" width="100px;" alt="Liam Lowsley-Williams"/><br /><sub><b>Liam Lowsley-Williams</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=liamlows" title="Code">💻</a> <a href="https://github.com/keycloakify/keycloakify/commits?author=liamlows" title="Documentation">📖</a></td>
134
134
  </tr>
135
+ <tr>
136
+ <td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/oes-rioniz/"><img src="https://avatars.githubusercontent.com/u/5172296?v=4?s=100" width="100px;" alt="Omid"/><br /><sub><b>Omid</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=uchar" title="Tests">⚠️</a> <a href="https://github.com/keycloakify/keycloakify/commits?author=uchar" title="Code">💻</a></td>
137
+ </tr>
135
138
  </tbody>
136
139
  </table>
137
140
 
package/bin/499.index.js CHANGED
@@ -785,6 +785,9 @@ var escapeStringForPropertiesFile = __webpack_require__(27190);
785
785
  // EXTERNAL MODULE: external "child_process"
786
786
  var external_child_process_ = __webpack_require__(32081);
787
787
  var external_child_process_default = /*#__PURE__*/__webpack_require__.n(external_child_process_);
788
+ // EXTERNAL MODULE: ./node_modules/properties-parser/index.js
789
+ var properties_parser = __webpack_require__(44414);
790
+ var properties_parser_default = /*#__PURE__*/__webpack_require__.n(properties_parser);
788
791
  ;// CONCATENATED MODULE: ./dist/bin/keycloakify/generateResources/generateResourcesForMainTheme.js
789
792
 
790
793
 
@@ -804,6 +807,7 @@ var external_child_process_default = /*#__PURE__*/__webpack_require__.n(external
804
807
 
805
808
 
806
809
 
810
+
807
811
  (0,assert.assert)();
808
812
  async function generateResourcesForMainTheme(params) {
809
813
  var _a;
@@ -937,14 +941,38 @@ async function generateResourcesForMainTheme(params) {
937
941
  })
938
942
  .toString("utf8")
939
943
  .trim();
940
- const messagesDirPath = (0,external_path_.join)(accountUiDirPath, "messages");
941
- if (!external_fs_.existsSync(messagesDirPath)) {
944
+ const messageDirPath_defaults = (0,external_path_.join)(accountUiDirPath, "messages");
945
+ if (!external_fs_.existsSync(messageDirPath_defaults)) {
942
946
  throw new Error(`Please update @keycloakify/keycloak-account-ui to 25.0.4-rc.5 or later.`);
943
947
  }
948
+ const messagesDirPath_dest = (0,external_path_.join)(getThemeTypeDirPath({ themeType: "account" }), "messages");
944
949
  (0,transformCodebase/* transformCodebase */.N)({
945
- srcDirPath: messagesDirPath,
946
- destDirPath: (0,external_path_.join)(getThemeTypeDirPath({ themeType: "account" }), "messages")
950
+ srcDirPath: messageDirPath_defaults,
951
+ destDirPath: messagesDirPath_dest
947
952
  });
953
+ apply_theme_changes: {
954
+ const messagesDirPath_theme = (0,external_path_.join)(buildContext.themeSrcDirPath, "account", "messages");
955
+ if (!external_fs_.existsSync(messagesDirPath_theme)) {
956
+ break apply_theme_changes;
957
+ }
958
+ external_fs_.readdirSync(messagesDirPath_theme).forEach(basename => {
959
+ const filePath_src = (0,external_path_.join)(messagesDirPath_theme, basename);
960
+ const filePath_dest = (0,external_path_.join)(messagesDirPath_dest, basename);
961
+ if (!external_fs_.existsSync(filePath_dest)) {
962
+ external_fs_.cpSync(filePath_src, filePath_dest);
963
+ }
964
+ const messages_src = properties_parser_default().parse(external_fs_.readFileSync(filePath_src).toString("utf8"));
965
+ const messages_dest = properties_parser_default().parse(external_fs_.readFileSync(filePath_dest).toString("utf8"));
966
+ const messages = Object.assign(Object.assign({}, messages_dest), messages_src);
967
+ const editor = properties_parser_default().createEditor();
968
+ Object.entries(messages).forEach(([key, value]) => {
969
+ editor.set(key, value);
970
+ });
971
+ external_fs_.writeFileSync(filePath_dest, Buffer.from(editor.toString(), "utf8"));
972
+ });
973
+ }
974
+ languageTags = external_fs_.readdirSync(messagesDirPath_dest)
975
+ .map(basename => basename.replace(/^messages_/, "").replace(/\.properties$/, ""));
948
976
  }
949
977
  keycloak_static_resources: {
950
978
  if (isForAccountSpa) {
@@ -1249,6 +1277,8 @@ function generatePom(params) {
1249
1277
  //# sourceMappingURL=generatePom.js.map
1250
1278
  // EXTERNAL MODULE: ./dist/bin/tools/isInside.js
1251
1279
  var isInside = __webpack_require__(90665);
1280
+ // EXTERNAL MODULE: ./dist/bin/tools/fs.existsAsync.js
1281
+ var fs_existsAsync = __webpack_require__(43765);
1252
1282
  ;// CONCATENATED MODULE: ./dist/bin/keycloakify/buildJars/buildJar.js
1253
1283
 
1254
1284
 
@@ -1260,6 +1290,7 @@ var isInside = __webpack_require__(90665);
1260
1290
 
1261
1291
 
1262
1292
 
1293
+
1263
1294
  (0,assert.assert)();
1264
1295
  async function buildJar(params) {
1265
1296
  const { jarFileBasename, keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, resourcesDirPath, doesImplementAccountV1Theme, buildContext } = params;
@@ -1314,8 +1345,13 @@ async function buildJar(params) {
1314
1345
  if (!buildContext.implementedThemeTypes.login.isImplemented) {
1315
1346
  break route_legacy_pages;
1316
1347
  }
1317
- ["register.ftl", "login-update-profile.ftl"].forEach(pageId => buildContext.themeNames.map(themeName => {
1348
+ await Promise.all(["register.ftl", "login-update-profile.ftl"]
1349
+ .map(pageId => buildContext.themeNames.map(async (themeName) => {
1318
1350
  const ftlFilePath = (0,external_path_.join)(tmpResourcesDirPath, "theme", themeName, "login", pageId);
1351
+ // NOTE: https://github.com/keycloakify/keycloakify/issues/665
1352
+ if (!(await (0,fs_existsAsync/* existsAsync */.o)(ftlFilePath))) {
1353
+ return;
1354
+ }
1319
1355
  const ftlFileContent = (0,external_fs_.readFileSync)(ftlFilePath).toString("utf8");
1320
1356
  const ftlFileBasename = (() => {
1321
1357
  switch (pageId) {
@@ -1328,8 +1364,9 @@ async function buildJar(params) {
1328
1364
  })();
1329
1365
  const modifiedFtlFileContent = ftlFileContent.replace(`"ftlTemplateFileName": "${pageId}"`, `"ftlTemplateFileName": "${ftlFileBasename}"`);
1330
1366
  (0,assert.assert)(modifiedFtlFileContent !== ftlFileContent);
1331
- promises_.writeFile((0,external_path_.join)((0,external_path_.dirname)(ftlFilePath), ftlFileBasename), Buffer.from(modifiedFtlFileContent, "utf8"));
1332
- }));
1367
+ await promises_.writeFile((0,external_path_.join)((0,external_path_.dirname)(ftlFilePath), ftlFileBasename), Buffer.from(modifiedFtlFileContent, "utf8"));
1368
+ }))
1369
+ .flat());
1333
1370
  }
1334
1371
  {
1335
1372
  const { pomFileCode } = generatePom({
@@ -1651,6 +1688,30 @@ function escapeStringForPropertiesFile(str) {
1651
1688
 
1652
1689
  /***/ }),
1653
1690
 
1691
+ /***/ 43765:
1692
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1693
+
1694
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1695
+ /* harmony export */ "o": () => (/* binding */ existsAsync)
1696
+ /* harmony export */ });
1697
+ /* harmony import */ var fs_promises__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(73292);
1698
+ /* harmony import */ var fs_promises__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs_promises__WEBPACK_IMPORTED_MODULE_0__);
1699
+
1700
+ async function existsAsync(path) {
1701
+ try {
1702
+ await fs_promises__WEBPACK_IMPORTED_MODULE_0__.stat(path);
1703
+ return true;
1704
+ }
1705
+ catch (error) {
1706
+ if (error.code === "ENOENT")
1707
+ return false;
1708
+ throw error;
1709
+ }
1710
+ }
1711
+ //# sourceMappingURL=fs.existsAsync.js.map
1712
+
1713
+ /***/ }),
1714
+
1654
1715
  /***/ 89693:
1655
1716
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1656
1717
 
@@ -1,5 +1,5 @@
1
- exports.id = 246;
2
- exports.ids = [246];
1
+ exports.id = 860;
2
+ exports.ids = [860];
3
3
  exports.modules = {
4
4
 
5
5
  /***/ 15573:
@@ -9292,6 +9292,434 @@ jsesc.version = '2.5.2';
9292
9292
  module.exports = jsesc;
9293
9293
 
9294
9294
 
9295
+ /***/ }),
9296
+
9297
+ /***/ 44414:
9298
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
9299
+
9300
+ __webpack_require__(21360);
9301
+ var fs = __webpack_require__(57147);
9302
+
9303
+ function Iterator(text) {
9304
+ var pos = 0, length = text.length;
9305
+
9306
+ this.peek = function(num) {
9307
+ num = num || 0;
9308
+ if(pos + num >= length) { return null; }
9309
+
9310
+ return text.charAt(pos + num);
9311
+ };
9312
+ this.next = function(inc) {
9313
+ inc = inc || 1;
9314
+
9315
+ if(pos >= length) { return null; }
9316
+
9317
+ return text.charAt((pos += inc) - inc);
9318
+ };
9319
+ this.pos = function() {
9320
+ return pos;
9321
+ };
9322
+ }
9323
+
9324
+ var rWhitespace = /\s/;
9325
+ function isWhitespace(chr) {
9326
+ return rWhitespace.test(chr);
9327
+ }
9328
+ function consumeWhiteSpace(iter) {
9329
+ var start = iter.pos();
9330
+
9331
+ while(isWhitespace(iter.peek())) { iter.next(); }
9332
+
9333
+ return { type: "whitespace", start: start, end: iter.pos() };
9334
+ }
9335
+
9336
+ function startsComment(chr) {
9337
+ return chr === "!" || chr === "#";
9338
+ }
9339
+ function isEOL(chr) {
9340
+ return chr == null || chr === "\n" || chr === "\r";
9341
+ }
9342
+ function consumeComment(iter) {
9343
+ var start = iter.pos();
9344
+
9345
+ while(!isEOL(iter.peek())) { iter.next(); }
9346
+
9347
+ return { type: "comment", start: start, end: iter.pos() };
9348
+ }
9349
+
9350
+ function startsKeyVal(chr) {
9351
+ return !isWhitespace(chr) && !startsComment(chr);
9352
+ }
9353
+ function startsSeparator(chr) {
9354
+ return chr === "=" || chr === ":" || isWhitespace(chr);
9355
+ }
9356
+ function startsEscapedVal(chr) {
9357
+ return chr === "\\";
9358
+ }
9359
+ function consumeEscapedVal(iter) {
9360
+ var start = iter.pos();
9361
+
9362
+ iter.next(); // move past "\"
9363
+ var curChar = iter.next();
9364
+ if(curChar === "u") { // encoded unicode char
9365
+ iter.next(4); // Read in the 4 hex values
9366
+ }
9367
+
9368
+ return { type: "escaped-value", start: start, end: iter.pos() };
9369
+ }
9370
+ function consumeKey(iter) {
9371
+ var start = iter.pos(), children = [];
9372
+
9373
+ var curChar;
9374
+ while((curChar = iter.peek()) !== null) {
9375
+ if(startsSeparator(curChar)) { break; }
9376
+ if(startsEscapedVal(curChar)) { children.push(consumeEscapedVal(iter)); continue; }
9377
+
9378
+ iter.next();
9379
+ }
9380
+
9381
+ return { type: "key", start: start, end: iter.pos(), children: children };
9382
+ }
9383
+ function consumeKeyValSeparator(iter) {
9384
+ var start = iter.pos();
9385
+
9386
+ var seenHardSep = false, curChar;
9387
+ while((curChar = iter.peek()) !== null) {
9388
+ if(isEOL(curChar)) { break; }
9389
+
9390
+ if(isWhitespace(curChar)) { iter.next(); continue; }
9391
+
9392
+ if(seenHardSep) { break; }
9393
+
9394
+ seenHardSep = (curChar === ":" || curChar === "=");
9395
+ if(seenHardSep) { iter.next(); continue; }
9396
+
9397
+ break; // curChar is a non-separtor char
9398
+ }
9399
+
9400
+ return { type: "key-value-separator", start: start, end: iter.pos() };
9401
+ }
9402
+ function startsLineBreak(iter) {
9403
+ return iter.peek() === "\\" && isEOL(iter.peek(1));
9404
+ }
9405
+ function consumeLineBreak(iter) {
9406
+ var start = iter.pos();
9407
+
9408
+ iter.next(); // consume \
9409
+ if(iter.peek() === "\r") { iter.next(); }
9410
+ iter.next(); // consume \n
9411
+
9412
+ var curChar;
9413
+ while((curChar = iter.peek()) !== null) {
9414
+ if(isEOL(curChar)) { break; }
9415
+ if(!isWhitespace(curChar)) { break; }
9416
+
9417
+ iter.next();
9418
+ }
9419
+
9420
+ return { type: "line-break", start: start, end: iter.pos() };
9421
+ }
9422
+ function consumeVal(iter) {
9423
+ var start = iter.pos(), children = [];
9424
+
9425
+ var curChar;
9426
+ while((curChar = iter.peek()) !== null) {
9427
+ if(startsLineBreak(iter)) { children.push(consumeLineBreak(iter)); continue; }
9428
+ if(startsEscapedVal(curChar)) { children.push(consumeEscapedVal(iter)); continue; }
9429
+ if(isEOL(curChar)) { break; }
9430
+
9431
+ iter.next();
9432
+ }
9433
+
9434
+ return { type: "value", start: start, end: iter.pos(), children: children };
9435
+ }
9436
+ function consumeKeyVal(iter) {
9437
+ return {
9438
+ type: "key-value",
9439
+ start: iter.pos(),
9440
+ children: [
9441
+ consumeKey(iter),
9442
+ consumeKeyValSeparator(iter),
9443
+ consumeVal(iter)
9444
+ ],
9445
+ end: iter.pos()
9446
+ };
9447
+ }
9448
+
9449
+ var renderChild = {
9450
+ "escaped-value": function(child, text) {
9451
+ var type = text.charAt(child.start + 1);
9452
+
9453
+ if(type === "t") { return "\t"; }
9454
+ if(type === "r") { return "\r"; }
9455
+ if(type === "n") { return "\n"; }
9456
+ if(type === "f") { return "\f"; }
9457
+ if(type !== "u") { return type; }
9458
+
9459
+ return String.fromCharCode(parseInt(text.substr(child.start + 2, 4), 16));
9460
+ },
9461
+ "line-break": function (child, text) {
9462
+ return "";
9463
+ }
9464
+ };
9465
+ function rangeToBuffer(range, text) {
9466
+ var start = range.start, buffer = [];
9467
+
9468
+ for(var i = 0; i < range.children.length; i++) {
9469
+ var child = range.children[i];
9470
+
9471
+ buffer.push(text.substring(start, child.start));
9472
+ buffer.push(renderChild[child.type](child, text));
9473
+ start = child.end;
9474
+ }
9475
+ buffer.push(text.substring(start, range.end));
9476
+
9477
+ return buffer;
9478
+ }
9479
+ function rangesToObject(ranges, text) {
9480
+ var obj = Object.create(null); // Creates to a true hash map
9481
+
9482
+ for(var i = 0; i < ranges.length; i++) {
9483
+ var range = ranges[i];
9484
+
9485
+ if(range.type !== "key-value") { continue; }
9486
+
9487
+ var key = rangeToBuffer(range.children[0], text).join("");
9488
+ var val = rangeToBuffer(range.children[2], text).join("");
9489
+ obj[key] = val;
9490
+ }
9491
+
9492
+ return obj;
9493
+ }
9494
+
9495
+ function stringToRanges(text) {
9496
+ var iter = new Iterator(text), ranges = [];
9497
+
9498
+ var curChar;
9499
+ while((curChar = iter.peek()) !== null) {
9500
+ if(isWhitespace(curChar)) { ranges.push(consumeWhiteSpace(iter)); continue; }
9501
+ if(startsComment(curChar)) { ranges.push(consumeComment(iter)); continue; }
9502
+ if(startsKeyVal(curChar)) { ranges.push(consumeKeyVal(iter)); continue; }
9503
+
9504
+ throw Error("Something crazy happened. text: '" + text + "'; curChar: '" + curChar + "'");
9505
+ }
9506
+
9507
+ return ranges;
9508
+ }
9509
+
9510
+ function isNewLineRange(range) {
9511
+ if(!range) { return false; }
9512
+
9513
+ if(range.type === "whitespace") { return true; }
9514
+
9515
+ if(range.type === "literal") {
9516
+ return isWhitespace(range.text) && range.text.indexOf("\n") > -1;
9517
+ }
9518
+
9519
+ return false;
9520
+ }
9521
+
9522
+ function escapeMaker(escapes) {
9523
+ return function escapeKey(key) {
9524
+ var zeros = [ "", "0", "00", "000" ];
9525
+ var buf = [];
9526
+
9527
+ for(var i = 0; i < key.length; i++) {
9528
+ var chr = key.charAt(i);
9529
+
9530
+ if(escapes[chr]) { buf.push(escapes[chr]); continue; }
9531
+
9532
+ var code = chr.codePointAt(0);
9533
+
9534
+ if(code <= 0x7F) { buf.push(chr); continue; }
9535
+
9536
+ var hex = code.toString(16);
9537
+
9538
+ buf.push("\\u");
9539
+ buf.push(zeros[4 - hex.length]);
9540
+ buf.push(hex);
9541
+ }
9542
+
9543
+ return buf.join("");
9544
+ };
9545
+ }
9546
+
9547
+ var escapeKey = escapeMaker({ " ": "\\ ", "\n": "\\n", ":": "\\:", "=": "\\=" });
9548
+ var escapeVal = escapeMaker({ "\n": "\\n" });
9549
+
9550
+ function Editor(text, options) {
9551
+ if (typeof text === 'object') {
9552
+ options = text;
9553
+ text = null;
9554
+ }
9555
+ text = text || "";
9556
+ var path = options.path;
9557
+ var separator = options.separator || '=';
9558
+
9559
+ var ranges = stringToRanges(text);
9560
+ var obj = rangesToObject(ranges, text);
9561
+ var keyRange = Object.create(null); // Creates to a true hash map
9562
+
9563
+ for(var i = 0; i < ranges.length; i++) {
9564
+ var range = ranges[i];
9565
+
9566
+ if(range.type !== "key-value") { continue; }
9567
+
9568
+ var key = rangeToBuffer(range.children[0], text).join("");
9569
+ keyRange[key] = range;
9570
+ }
9571
+
9572
+ this.addHeadComment = function(comment) {
9573
+ if(comment == null) { return; }
9574
+
9575
+ ranges.unshift({ type: "literal", text: "# " + comment.replace(/\n/g, "\n# ") + "\n" });
9576
+ };
9577
+
9578
+ this.get = function(key) { return obj[key]; };
9579
+ this.set = function(key, val, comment) {
9580
+ if(val == null) { this.unset(key); return; }
9581
+
9582
+ obj[key] = val;
9583
+ var escapedKey = escapeKey(key);
9584
+ var escapedVal = escapeVal(val);
9585
+
9586
+ var range = keyRange[key];
9587
+ if(!range) {
9588
+ keyRange[key] = range = {
9589
+ type: "literal",
9590
+ text: escapedKey + separator + escapedVal
9591
+ };
9592
+
9593
+ var prevRange = ranges[ranges.length - 1];
9594
+ if(prevRange != null && !isNewLineRange(prevRange)) {
9595
+ ranges.push({ type: "literal", text: "\n" });
9596
+ }
9597
+ ranges.push(range);
9598
+ }
9599
+
9600
+ // comment === null deletes comment. if comment === undefined, it's left alone
9601
+ if(comment !== undefined) {
9602
+ range.comment = comment && "# " + comment.replace(/\n/g, "\n# ") + "\n";
9603
+ }
9604
+
9605
+ if(range.type === "literal") {
9606
+ range.text = escapedKey + separator + escapedVal;
9607
+ if(range.comment != null) { range.text = range.comment + range.text; }
9608
+ } else if(range.type === "key-value") {
9609
+ range.children[2] = { type: "literal", text: escapedVal };
9610
+ } else {
9611
+ throw "Unknown node type: " + range.type;
9612
+ }
9613
+ };
9614
+ this.unset = function(key) {
9615
+ if(!(key in obj)) { return; }
9616
+
9617
+ var range = keyRange[key];
9618
+ var idx = ranges.indexOf(range);
9619
+
9620
+ ranges.splice(idx, (isNewLineRange(ranges[idx + 1]) ? 2 : 1));
9621
+
9622
+ delete keyRange[key];
9623
+ delete obj[key];
9624
+ };
9625
+ this.valueOf = this.toString = function() {
9626
+ var buffer = [], stack = [].concat(ranges);
9627
+
9628
+ var node;
9629
+ while((node = stack.shift()) != null) {
9630
+ switch(node.type) {
9631
+ case "literal":
9632
+ buffer.push(node.text);
9633
+ break;
9634
+ case "key":
9635
+ case "value":
9636
+ case "comment":
9637
+ case "whitespace":
9638
+ case "key-value-separator":
9639
+ case "escaped-value":
9640
+ case "line-break":
9641
+ buffer.push(text.substring(node.start, node.end));
9642
+ break;
9643
+ case "key-value":
9644
+ Array.prototype.unshift.apply(stack, node.children);
9645
+ if(node.comment) { stack.unshift({ type: "literal", text: node.comment }); }
9646
+ break;
9647
+ }
9648
+ }
9649
+
9650
+ return buffer.join("");
9651
+ };
9652
+ this.save = function(newPath, callback) {
9653
+ if(typeof newPath === 'function') {
9654
+ callback = newPath;
9655
+ newPath = path;
9656
+ }
9657
+ newPath = newPath || path;
9658
+
9659
+ if(!newPath) {
9660
+ if (callback) {
9661
+ return callback("Unknown path");
9662
+ }
9663
+ throw new Error("Unknown path");
9664
+ }
9665
+
9666
+ if (callback) {
9667
+ fs.writeFile(newPath, this.toString(), callback);
9668
+ } else {
9669
+ fs.writeFileSync(newPath, this.toString());
9670
+ }
9671
+
9672
+ };
9673
+ }
9674
+ function createEditor(/*path, options, callback*/) {
9675
+ var path, options, callback;
9676
+ var args = Array.prototype.slice.call(arguments);
9677
+ for (var i = 0; i < args.length; i ++) {
9678
+ var arg = args[i];
9679
+ if (!path && typeof arg === 'string') {
9680
+ path = arg;
9681
+ } else if (!options && typeof arg === 'object') {
9682
+ options = arg;
9683
+ } else if (!callback && typeof arg === 'function') {
9684
+ callback = arg;
9685
+ }
9686
+ }
9687
+ options = options || {};
9688
+ path = path || options.path;
9689
+ callback = callback || options.callback;
9690
+ options.path = path;
9691
+
9692
+ if(!path) { return new Editor(options); }
9693
+
9694
+ if(!callback) { return new Editor(fs.readFileSync(path).toString(), options); }
9695
+
9696
+ return fs.readFile(path, function(err, text) {
9697
+ if(err) { return callback(err, null); }
9698
+
9699
+ text = text.toString();
9700
+ return callback(null, new Editor(text, options));
9701
+ });
9702
+ }
9703
+
9704
+ function parse(text) {
9705
+ text = text.toString();
9706
+ var ranges = stringToRanges(text);
9707
+ return rangesToObject(ranges, text);
9708
+ }
9709
+
9710
+ function read(path, callback) {
9711
+ if(!callback) { return parse(fs.readFileSync(path)); }
9712
+
9713
+ return fs.readFile(path, function(err, data) {
9714
+ if(err) { return callback(err, null); }
9715
+
9716
+ return callback(null, parse(data));
9717
+ });
9718
+ }
9719
+
9720
+ module.exports = { parse: parse, read: read, createEditor: createEditor };
9721
+
9722
+
9295
9723
  /***/ }),
9296
9724
 
9297
9725
  /***/ 11346:
@@ -22663,6 +23091,67 @@ exports.SourceMapConsumer = __webpack_require__(75155).SourceMapConsumer;
22663
23091
  exports.SourceNode = __webpack_require__(92616).SourceNode;
22664
23092
 
22665
23093
 
23094
+ /***/ }),
23095
+
23096
+ /***/ 21360:
23097
+ /***/ (() => {
23098
+
23099
+ /*! https://mths.be/codepointat v0.2.0 by @mathias */
23100
+ if (!String.prototype.codePointAt) {
23101
+ (function() {
23102
+ 'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
23103
+ var defineProperty = (function() {
23104
+ // IE 8 only supports `Object.defineProperty` on DOM elements
23105
+ try {
23106
+ var object = {};
23107
+ var $defineProperty = Object.defineProperty;
23108
+ var result = $defineProperty(object, object, object) && $defineProperty;
23109
+ } catch(error) {}
23110
+ return result;
23111
+ }());
23112
+ var codePointAt = function(position) {
23113
+ if (this == null) {
23114
+ throw TypeError();
23115
+ }
23116
+ var string = String(this);
23117
+ var size = string.length;
23118
+ // `ToInteger`
23119
+ var index = position ? Number(position) : 0;
23120
+ if (index != index) { // better `isNaN`
23121
+ index = 0;
23122
+ }
23123
+ // Account for out-of-bounds indices:
23124
+ if (index < 0 || index >= size) {
23125
+ return undefined;
23126
+ }
23127
+ // Get the first code unit
23128
+ var first = string.charCodeAt(index);
23129
+ var second;
23130
+ if ( // check if it’s the start of a surrogate pair
23131
+ first >= 0xD800 && first <= 0xDBFF && // high surrogate
23132
+ size > index + 1 // there is a next code unit
23133
+ ) {
23134
+ second = string.charCodeAt(index + 1);
23135
+ if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
23136
+ // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
23137
+ return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
23138
+ }
23139
+ }
23140
+ return first;
23141
+ };
23142
+ if (defineProperty) {
23143
+ defineProperty(String.prototype, 'codePointAt', {
23144
+ 'value': codePointAt,
23145
+ 'configurable': true,
23146
+ 'writable': true
23147
+ });
23148
+ } else {
23149
+ String.prototype.codePointAt = codePointAt;
23150
+ }
23151
+ }());
23152
+ }
23153
+
23154
+
22666
23155
  /***/ }),
22667
23156
 
22668
23157
  /***/ 19049:
package/bin/main.js CHANGED
@@ -11312,7 +11312,7 @@ program
11312
11312
  .task({
11313
11313
  skip,
11314
11314
  handler: async (cliCommandOptions) => {
11315
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(941), __nccwpck_require__.e(246), __nccwpck_require__.e(31), __nccwpck_require__.e(499)]).then(__nccwpck_require__.bind(__nccwpck_require__, 70499));
11315
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(941), __nccwpck_require__.e(860), __nccwpck_require__.e(31), __nccwpck_require__.e(499)]).then(__nccwpck_require__.bind(__nccwpck_require__, 70499));
11316
11316
  await command({ cliCommandOptions });
11317
11317
  }
11318
11318
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keycloakify",
3
- "version": "11.0.0",
3
+ "version": "11.1.0",
4
4
  "description": "Framework to create custom Keycloak UIs",
5
5
  "repository": {
6
6
  "type": "git",
@@ -981,7 +981,6 @@
981
981
  "bin/main.js",
982
982
  "bin/193.index.js",
983
983
  "bin/20.index.js",
984
- "bin/246.index.js",
985
984
  "bin/266.index.js",
986
985
  "bin/304.index.js",
987
986
  "bin/31.index.js",
@@ -995,6 +994,7 @@
995
994
  "bin/743.index.js",
996
995
  "bin/780.index.js",
997
996
  "bin/786.index.js",
997
+ "bin/860.index.js",
998
998
  "bin/877.index.js",
999
999
  "bin/903.index.js",
1000
1000
  "bin/932.index.js",
@@ -1040,6 +1040,7 @@
1040
1040
  "@babel/core": "^7.24.5",
1041
1041
  "@babel/generator": "^7.24.5",
1042
1042
  "@babel/parser": "^7.24.5",
1043
+ "@babel/preset-env": "7.24.8",
1043
1044
  "@babel/types": "^7.24.5",
1044
1045
  "@emotion/react": "^11.11.4",
1045
1046
  "@octokit/rest": "^20.1.1",
@@ -1047,20 +1048,27 @@
1047
1048
  "@storybook/builder-webpack5": "^6.5.13",
1048
1049
  "@storybook/manager-webpack5": "^6.5.13",
1049
1050
  "@storybook/react": "^6.5.13",
1050
- "eslint-plugin-storybook": "^0.6.7",
1051
1051
  "@types/babel__generator": "^7.6.4",
1052
+ "@types/dompurify": "^2.0.0",
1052
1053
  "@types/make-fetch-happen": "^10.0.1",
1053
1054
  "@types/minimist": "^1.2.2",
1054
1055
  "@types/node": "^18.15.3",
1056
+ "@types/properties-parser": "^0.3.3",
1055
1057
  "@types/react": "^18.0.35",
1056
1058
  "@types/react-dom": "^18.0.11",
1057
1059
  "@types/yauzl": "^2.10.3",
1058
1060
  "@vercel/ncc": "^0.38.1",
1061
+ "babel-loader": "9.1.3",
1059
1062
  "chalk": "^4.1.2",
1060
1063
  "cheerio": "1.0.0-rc.12",
1061
1064
  "chokidar-cli": "^3.0.0",
1062
1065
  "cli-select": "^1.1.2",
1066
+ "dompurify": "^3.1.6",
1067
+ "eslint-plugin-storybook": "^0.6.7",
1068
+ "evt": "^2.5.7",
1069
+ "html-entities": "^2.5.2",
1063
1070
  "husky": "^4.3.8",
1071
+ "isomorphic-dompurify": "^2.15.0",
1064
1072
  "lint-staged": "^11.0.0",
1065
1073
  "magic-string": "^0.30.7",
1066
1074
  "make-fetch-happen": "^11.0.3",
@@ -1075,20 +1083,13 @@
1075
1083
  "termost": "^v0.12.1",
1076
1084
  "tsc-alias": "^1.8.10",
1077
1085
  "tss-react": "^4.9.10",
1086
+ "tsx": "^4.15.5",
1078
1087
  "typescript": "^4.9.4",
1079
1088
  "vite": "^5.2.11",
1080
1089
  "vitest": "^1.6.0",
1081
- "yauzl": "^2.10.0",
1082
- "zod": "^3.17.10",
1083
- "evt": "^2.5.7",
1084
- "tsx": "^4.15.5",
1085
- "html-entities": "^2.5.2",
1086
- "isomorphic-dompurify": "^2.15.0",
1087
- "dompurify": "^3.1.6",
1088
- "@types/dompurify": "^2.0.0",
1089
1090
  "webpack": "5.93.0",
1090
1091
  "webpack-cli": "5.1.4",
1091
- "babel-loader": "9.1.3",
1092
- "@babel/preset-env": "7.24.8"
1092
+ "yauzl": "^2.10.0",
1093
+ "zod": "^3.17.10"
1093
1094
  }
1094
1095
  }
@@ -16,6 +16,7 @@ import { isInside } from "../../tools/isInside";
16
16
  import child_process from "child_process";
17
17
  import { rmSync } from "../../tools/fs.rmSync";
18
18
  import { writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
19
+ import { existsAsync } from "../../tools/fs.existsAsync";
19
20
 
20
21
  export type BuildContextLike = BuildContextLike_generatePom & {
21
22
  keycloakifyBuildDirPath: string;
@@ -135,40 +136,49 @@ export async function buildJar(params: {
135
136
  break route_legacy_pages;
136
137
  }
137
138
 
138
- (["register.ftl", "login-update-profile.ftl"] as const).forEach(pageId =>
139
- buildContext.themeNames.map(themeName => {
140
- const ftlFilePath = pathJoin(
141
- tmpResourcesDirPath,
142
- "theme",
143
- themeName,
144
- "login",
145
- pageId
146
- );
147
-
148
- const ftlFileContent = readFileSync(ftlFilePath).toString("utf8");
149
-
150
- const ftlFileBasename = (() => {
151
- switch (pageId) {
152
- case "register.ftl":
153
- return "register-user-profile.ftl";
154
- case "login-update-profile.ftl":
155
- return "update-user-profile.ftl";
156
- }
157
- assert<Equals<typeof pageId, never>>(false);
158
- })();
159
-
160
- const modifiedFtlFileContent = ftlFileContent.replace(
161
- `"ftlTemplateFileName": "${pageId}"`,
162
- `"ftlTemplateFileName": "${ftlFileBasename}"`
163
- );
164
-
165
- assert(modifiedFtlFileContent !== ftlFileContent);
166
-
167
- fs.writeFile(
168
- pathJoin(pathDirname(ftlFilePath), ftlFileBasename),
169
- Buffer.from(modifiedFtlFileContent, "utf8")
170
- );
171
- })
139
+ await Promise.all(
140
+ (["register.ftl", "login-update-profile.ftl"] as const)
141
+ .map(pageId =>
142
+ buildContext.themeNames.map(async themeName => {
143
+ const ftlFilePath = pathJoin(
144
+ tmpResourcesDirPath,
145
+ "theme",
146
+ themeName,
147
+ "login",
148
+ pageId
149
+ );
150
+
151
+ // NOTE: https://github.com/keycloakify/keycloakify/issues/665
152
+ if (!(await existsAsync(ftlFilePath))) {
153
+ return;
154
+ }
155
+
156
+ const ftlFileContent = readFileSync(ftlFilePath).toString("utf8");
157
+
158
+ const ftlFileBasename = (() => {
159
+ switch (pageId) {
160
+ case "register.ftl":
161
+ return "register-user-profile.ftl";
162
+ case "login-update-profile.ftl":
163
+ return "update-user-profile.ftl";
164
+ }
165
+ assert<Equals<typeof pageId, never>>(false);
166
+ })();
167
+
168
+ const modifiedFtlFileContent = ftlFileContent.replace(
169
+ `"ftlTemplateFileName": "${pageId}"`,
170
+ `"ftlTemplateFileName": "${ftlFileBasename}"`
171
+ );
172
+
173
+ assert(modifiedFtlFileContent !== ftlFileContent);
174
+
175
+ await fs.writeFile(
176
+ pathJoin(pathDirname(ftlFilePath), ftlFileBasename),
177
+ Buffer.from(modifiedFtlFileContent, "utf8")
178
+ );
179
+ })
180
+ )
181
+ .flat()
172
182
  );
173
183
  }
174
184
 
@@ -31,6 +31,7 @@ import { objectEntries } from "tsafe/objectEntries";
31
31
  import { escapeStringForPropertiesFile } from "../../tools/escapeStringForPropertiesFile";
32
32
  import * as child_process from "child_process";
33
33
  import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
34
+ import propertiesParser from "properties-parser";
34
35
 
35
36
  export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
36
37
  BuildContextLike_generateMessageProperties & {
@@ -239,21 +240,73 @@ export async function generateResourcesForMainTheme(params: {
239
240
  .toString("utf8")
240
241
  .trim();
241
242
 
242
- const messagesDirPath = pathJoin(accountUiDirPath, "messages");
243
+ const messageDirPath_defaults = pathJoin(accountUiDirPath, "messages");
243
244
 
244
- if (!fs.existsSync(messagesDirPath)) {
245
+ if (!fs.existsSync(messageDirPath_defaults)) {
245
246
  throw new Error(
246
247
  `Please update @keycloakify/keycloak-account-ui to 25.0.4-rc.5 or later.`
247
248
  );
248
249
  }
249
250
 
251
+ const messagesDirPath_dest = pathJoin(
252
+ getThemeTypeDirPath({ themeType: "account" }),
253
+ "messages"
254
+ );
255
+
250
256
  transformCodebase({
251
- srcDirPath: messagesDirPath,
252
- destDirPath: pathJoin(
253
- getThemeTypeDirPath({ themeType: "account" }),
254
- "messages"
255
- )
257
+ srcDirPath: messageDirPath_defaults,
258
+ destDirPath: messagesDirPath_dest
256
259
  });
260
+
261
+ apply_theme_changes: {
262
+ const messagesDirPath_theme = pathJoin(
263
+ buildContext.themeSrcDirPath,
264
+ "account",
265
+ "messages"
266
+ );
267
+
268
+ if (!fs.existsSync(messagesDirPath_theme)) {
269
+ break apply_theme_changes;
270
+ }
271
+
272
+ fs.readdirSync(messagesDirPath_theme).forEach(basename => {
273
+ const filePath_src = pathJoin(messagesDirPath_theme, basename);
274
+ const filePath_dest = pathJoin(messagesDirPath_dest, basename);
275
+
276
+ if (!fs.existsSync(filePath_dest)) {
277
+ fs.cpSync(filePath_src, filePath_dest);
278
+ }
279
+
280
+ const messages_src = propertiesParser.parse(
281
+ fs.readFileSync(filePath_src).toString("utf8")
282
+ );
283
+ const messages_dest = propertiesParser.parse(
284
+ fs.readFileSync(filePath_dest).toString("utf8")
285
+ );
286
+
287
+ const messages = {
288
+ ...messages_dest,
289
+ ...messages_src
290
+ };
291
+
292
+ const editor = propertiesParser.createEditor();
293
+
294
+ Object.entries(messages).forEach(([key, value]) => {
295
+ editor.set(key, value);
296
+ });
297
+
298
+ fs.writeFileSync(
299
+ filePath_dest,
300
+ Buffer.from(editor.toString(), "utf8")
301
+ );
302
+ });
303
+ }
304
+
305
+ languageTags = fs
306
+ .readdirSync(messagesDirPath_dest)
307
+ .map(basename =>
308
+ basename.replace(/^messages_/, "").replace(/\.properties$/, "")
309
+ );
257
310
  }
258
311
 
259
312
  keycloak_static_resources: {