pxt-core 7.4.9 → 7.4.13

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.
Files changed (59) hide show
  1. package/built/cli.js +94 -83
  2. package/built/pxt.js +180 -135
  3. package/built/pxtblockly.js +1509 -1508
  4. package/built/pxtblocks.d.ts +11 -4
  5. package/built/pxtblocks.js +126 -138
  6. package/built/pxtlib.d.ts +6 -2
  7. package/built/pxtlib.js +86 -52
  8. package/built/target.js +1 -1
  9. package/built/web/blockly.css +1 -1
  10. package/built/web/main.js +1 -1
  11. package/built/web/pxtapp.js +1 -1
  12. package/built/web/pxtasseteditor.js +1 -1
  13. package/built/web/pxtblockly.js +53 -1
  14. package/built/web/pxtblocks.js +1 -1
  15. package/built/web/pxtembed.js +53 -1
  16. package/built/web/pxtlib.js +1 -1
  17. package/built/web/pxtworker.js +1 -1
  18. package/built/web/react-common-skillmap.css +1 -0
  19. package/built/web/rtlblockly.css +1 -1
  20. package/built/web/rtlreact-common-skillmap.css +1 -0
  21. package/built/web/rtlsemantic.css +1 -1
  22. package/built/web/semantic.css +1 -1
  23. package/built/web/skillmap/js/main.b96caef3.chunk.js +1 -0
  24. package/docfiles/tracking.html +1 -1
  25. package/localtypings/blockly.d.ts +12268 -7535
  26. package/localtypings/pxtarget.d.ts +1 -0
  27. package/localtypings/pxtblockly.d.ts +37 -0
  28. package/package.json +6 -3
  29. package/react-common/components/Checkbox.tsx +25 -0
  30. package/react-common/components/Notification.tsx +82 -0
  31. package/react-common/components/profile/Badge.tsx +33 -0
  32. package/react-common/components/profile/BadgeInfo.tsx +74 -0
  33. package/react-common/components/profile/BadgeList.tsx +67 -0
  34. package/react-common/components/profile/Profile.tsx +42 -0
  35. package/react-common/components/profile/UserNotification.tsx +32 -0
  36. package/react-common/components/profile/UserPane.tsx +64 -0
  37. package/react-common/components/types.d.ts +29 -0
  38. package/react-common/components/util.tsx +35 -0
  39. package/{built/web/react-common.css → react-common/styles/profile/profile.less} +1 -0
  40. package/react-common/styles/react-common-skillmap-core.less +10 -0
  41. package/react-common/styles/react-common-skillmap.less +12 -0
  42. package/react-common/styles/react-common.less +1 -0
  43. package/react-common/tsconfig.json +36 -0
  44. package/theme/blockly-core.less +38 -13
  45. package/theme/common-components.less +7 -0
  46. package/theme/common.less +1 -1
  47. package/theme/highcontrast.less +4 -0
  48. package/theme/melodyeditor.less +2 -2
  49. package/theme/print.less +1 -1
  50. package/theme/pxt.less +2 -0
  51. package/theme/toolbox.less +1 -0
  52. package/theme/tutorial-sidebar.less +64 -6
  53. package/webapp/public/blockly/blockly_compressed.js +1271 -1288
  54. package/webapp/public/blockly/blocks_compressed.js +47 -65
  55. package/webapp/public/blockly/msg/js/en.js +8 -17
  56. package/webapp/public/blockly/msg/json/en.json +6 -15
  57. package/webapp/public/blockly/plugins.js +57 -0
  58. package/webapp/public/skillmap.html +2 -2
  59. package/built/web/skillmap/js/main.ea4b3e23.chunk.js +0 -1
package/built/pxt.js CHANGED
@@ -97885,7 +97885,7 @@ var pxt;
97885
97885
  constructor() {
97886
97886
  this.initialUserPreferences_ = undefined;
97887
97887
  this.initialAuthCheck_ = undefined;
97888
- this.prefPatchOps = [];
97888
+ this.patchQueue = [];
97889
97889
  pxt.Util.assert(!_client);
97890
97890
  // Set global instance.
97891
97891
  _client = this;
@@ -98075,63 +98075,85 @@ var pxt;
98075
98075
  }
98076
98076
  return result.success;
98077
98077
  }
98078
- async patchUserPreferencesAsync(ops, immediate = false) {
98079
- ops = Array.isArray(ops) ? ops : [ops];
98080
- ops = ops.filter(op => !!op);
98078
+ async patchUserPreferencesAsync(patchOps, opts = {}) {
98079
+ const defaultSuccessAsync = async () => ({ success: true, res: await this.userPreferencesAsync() });
98080
+ patchOps = Array.isArray(patchOps) ? patchOps : [patchOps];
98081
+ patchOps = patchOps.filter(op => !!op);
98082
+ if (!patchOps.length) {
98083
+ return await defaultSuccessAsync();
98084
+ }
98085
+ const patchDiff = (pSrc, ops, filter) => {
98086
+ // Apply patches to pDst and return the diff as a set of new patch ops.
98087
+ const pDst = pxt.U.deepCopy(pSrc);
98088
+ ts.pxtc.jsonPatch.patchInPlace(pDst, ops);
98089
+ let diff = ts.pxtc.jsonPatch.diff(pSrc, pDst);
98090
+ // Run caller-provided filter
98091
+ if (diff.length && filter) {
98092
+ diff = diff.filter(filter);
98093
+ }
98094
+ return diff;
98095
+ };
98096
+ // Process incoming patch operations to produce a more fine-grained set of diffs. Incoming patches may be overly destructive
98097
+ // Apply the patch in isolation and get the diff from original
98081
98098
  const curPref = await this.userPreferencesAsync();
98082
- if (!ops.length) {
98083
- return { success: true, res: curPref };
98099
+ const diff = patchDiff(curPref, patchOps, opts.filter);
98100
+ if (!diff.length) {
98101
+ return await defaultSuccessAsync();
98084
98102
  }
98085
- ts.pxtc.jsonPatch.patchInPlace(curPref, ops);
98103
+ // Apply the new diff to the current state
98104
+ ts.pxtc.jsonPatch.patchInPlace(curPref, diff);
98086
98105
  await this.setUserPreferencesAsync(curPref);
98087
- // If we're not logged in, non-persistent local state is all we'll use
98106
+ // If the user is not logged in, non-persistent local state is all we'll use (no sync to cloud)
98088
98107
  if (!await this.loggedInAsync()) {
98089
- return { success: true, res: curPref };
98108
+ return await defaultSuccessAsync();
98090
98109
  }
98091
- // If the user is logged in, save to cloud, but debounce the api call as this can be called frequently from skillmaps
98092
- // Replace matching patches in the queue
98093
- ops.forEach((incoming, iIncoming) => {
98094
- this.prefPatchOps.some((existing, iExisting) => {
98095
- if (!ts.pxtc.jsonPatch.opsAreEqual(existing, incoming))
98096
- return false;
98097
- // Patches are equivalent, replace in queue
98098
- this.prefPatchOps[iExisting] = incoming;
98099
- // Clear from incoming so we don't add it below
98100
- ops[iIncoming] = null;
98101
- return true;
98102
- });
98103
- });
98104
- // Add remaining ops to the queue
98105
- ops.filter(op => !!op).forEach(op => this.prefPatchOps.push(op));
98110
+ // If the user is logged in, sync to cloud, but debounce the api call as this can be called frequently from skillmaps
98111
+ // Queue the patch for sync with backend
98112
+ this.patchQueue.push({ ops: patchOps, filter: opts.filter });
98106
98113
  clearTimeout(debouncePreferencesChangedTimeout);
98107
- const savePrefs = async () => {
98114
+ const syncPrefs = async () => {
98108
98115
  debouncePreferencesChangedStarted = 0;
98109
- // Clear queued patch ops before send.
98110
- const prefPatchOps = this.prefPatchOps;
98111
- this.prefPatchOps = [];
98112
- const result = await this.apiAsync('/api/user/preferences', prefPatchOps, 'PATCH');
98113
- if (result.success) {
98114
- pxt.debug("Updating local user preferences w/ cloud data after result of POST");
98115
- // Set user profile from returned value so we stay in-sync
98116
- this.setUserPreferencesAsync(result.resp);
98116
+ if (!this.patchQueue.length) {
98117
+ return await defaultSuccessAsync();
98118
+ }
98119
+ // Fetch latest prefs from remote
98120
+ const getResult = await this.apiAsync('/api/user/preferences');
98121
+ if (!getResult.success) {
98122
+ pxt.reportError("identity", "failed to fetch preferences for patch", getResult);
98123
+ return { success: false, res: undefined };
98124
+ }
98125
+ // Apply queued patches to the remote state in isolation and develop a final diff to send to the backend
98126
+ const remotePrefs = pxt.U.deepCopy(getResult.resp) || auth.DEFAULT_USER_PREFERENCES();
98127
+ const patchQueue = this.patchQueue;
98128
+ this.patchQueue = []; // Reset the queue
98129
+ patchQueue.forEach(patch => {
98130
+ const diff = patchDiff(remotePrefs, patch.ops, patch.filter);
98131
+ ts.pxtc.jsonPatch.patchInPlace(remotePrefs, diff);
98132
+ });
98133
+ // Diff the original and patched remote states to get a final set of patch operations
98134
+ const finalOps = pxtc.jsonPatch.diff(getResult.resp, remotePrefs);
98135
+ const patchResult = await this.apiAsync('/api/user/preferences', finalOps, 'PATCH');
98136
+ if (patchResult.success) {
98137
+ // Set user profile from returned value so we stay in sync
98138
+ this.setUserPreferencesAsync(patchResult.resp);
98117
98139
  }
98118
98140
  else {
98119
- pxt.reportError("identity", "update preferences failed", result);
98141
+ pxt.reportError("identity", "failed to patch preferences", patchResult);
98120
98142
  }
98121
- return { success: result.success, res: result.resp };
98143
+ return { success: patchResult.success, res: patchResult.resp };
98122
98144
  };
98123
- if (immediate) {
98124
- return await savePrefs();
98145
+ if (opts.immediate) {
98146
+ return await syncPrefs();
98125
98147
  }
98126
98148
  else {
98127
98149
  if (!debouncePreferencesChangedStarted) {
98128
98150
  debouncePreferencesChangedStarted = pxt.U.now();
98129
98151
  }
98130
98152
  if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
98131
- return await savePrefs();
98153
+ return await syncPrefs();
98132
98154
  }
98133
98155
  else {
98134
- debouncePreferencesChangedTimeout = setTimeout(savePrefs, PREFERENCES_DEBOUNCE_MS);
98156
+ debouncePreferencesChangedTimeout = setTimeout(syncPrefs, PREFERENCES_DEBOUNCE_MS);
98135
98157
  return { success: false, res: undefined }; // This needs to be implemented correctly to return a promise with the debouncer
98136
98158
  }
98137
98159
  }
@@ -99214,6 +99236,18 @@ var ts;
99214
99236
  return r;
99215
99237
  }
99216
99238
  Util.toSet = toSet;
99239
+ function deepCopy(src) {
99240
+ if (typeof src !== "object" || src === null) {
99241
+ return src;
99242
+ }
99243
+ const dst = Array.isArray(src) ? [] : {};
99244
+ for (const key in src) {
99245
+ const value = src[key];
99246
+ dst[key] = deepCopy(value);
99247
+ }
99248
+ return dst;
99249
+ }
99250
+ Util.deepCopy = deepCopy;
99217
99251
  function toArray(a) {
99218
99252
  if (Array.isArray(a)) {
99219
99253
  return a;
@@ -101633,7 +101667,7 @@ var pxt;
101633
101667
  'pxt_controls_for': {
101634
101668
  name: pxt.Util.lf("a loop that repeats the number of times you say"),
101635
101669
  tooltip: pxt.Util.lf("Have the variable '{0}' take on the values from 0 to the end number, counting by 1, and do the specified blocks."),
101636
- url: 'blocks/loops/for',
101670
+ url: '/blocks/loops/for',
101637
101671
  category: 'loops',
101638
101672
  block: {
101639
101673
  message0: pxt.Util.lf("for %1 from 0 to %2"),
@@ -101644,7 +101678,7 @@ var pxt;
101644
101678
  'controls_simple_for': {
101645
101679
  name: pxt.Util.lf("a loop that repeats the number of times you say"),
101646
101680
  tooltip: pxt.Util.lf("Have the variable '{0}' take on the values from 0 to the end number, counting by 1, and do the specified blocks."),
101647
- url: 'blocks/loops/for',
101681
+ url: '/blocks/loops/for',
101648
101682
  category: 'loops',
101649
101683
  block: {
101650
101684
  message0: pxt.Util.lf("for %1 from 0 to %2"),
@@ -101655,7 +101689,7 @@ var pxt;
101655
101689
  'pxt_controls_for_of': {
101656
101690
  name: pxt.Util.lf("a loop that repeats for each value in an array"),
101657
101691
  tooltip: pxt.Util.lf("Have the variable '{0}' take the value of each item in the array one by one, and do the specified blocks."),
101658
- url: 'blocks/loops/for-of',
101692
+ url: '/blocks/loops/for-of',
101659
101693
  category: 'loops',
101660
101694
  block: {
101661
101695
  message0: pxt.Util.lf("for element %1 of %2"),
@@ -101666,7 +101700,7 @@ var pxt;
101666
101700
  'controls_for_of': {
101667
101701
  name: pxt.Util.lf("a loop that repeats for each value in an array"),
101668
101702
  tooltip: pxt.Util.lf("Have the variable '{0}' take the value of each item in the array one by one, and do the specified blocks."),
101669
- url: 'blocks/loops/for-of',
101703
+ url: '/blocks/loops/for-of',
101670
101704
  category: 'loops',
101671
101705
  block: {
101672
101706
  message0: pxt.Util.lf("for element %1 of %2"),
@@ -101951,7 +101985,7 @@ var pxt;
101951
101985
  'text': {
101952
101986
  name: pxt.Util.lf("a piece of text"),
101953
101987
  tooltip: pxt.Util.lf("A letter, word, or line of text."),
101954
- url: 'types/string',
101988
+ url: '/types/string',
101955
101989
  category: 'text',
101956
101990
  block: {
101957
101991
  search: pxt.Util.lf("a piece of text") // Only used for search; this string is not surfaced in the block's text
@@ -101960,7 +101994,7 @@ var pxt;
101960
101994
  'text_length': {
101961
101995
  name: pxt.Util.lf("number of characters in the string"),
101962
101996
  tooltip: pxt.Util.lf("Returns the number of letters (including spaces) in the provided text."),
101963
- url: 'reference/text/length',
101997
+ url: '/reference/text/length',
101964
101998
  category: 'text',
101965
101999
  block: {
101966
102000
  TEXT_LENGTH_TITLE: pxt.Util.lf("length of %1")
@@ -101969,7 +102003,7 @@ var pxt;
101969
102003
  'text_join': {
101970
102004
  name: pxt.Util.lf("join items to create text"),
101971
102005
  tooltip: pxt.Util.lf("Create a piece of text by joining together any number of items."),
101972
- url: 'reference/text/join',
102006
+ url: '/reference/text/join',
101973
102007
  category: 'text',
101974
102008
  block: {
101975
102009
  TEXT_JOIN_TITLE_CREATEWITH: pxt.Util.lf("join")
@@ -101978,7 +102012,7 @@ var pxt;
101978
102012
  'procedures_defnoreturn': {
101979
102013
  name: pxt.Util.lf("define the function"),
101980
102014
  tooltip: pxt.Util.lf("Create a function."),
101981
- url: 'types/function/define',
102015
+ url: '/types/function/define',
101982
102016
  category: 'functions',
101983
102017
  block: {
101984
102018
  PROCEDURES_DEFNORETURN_TITLE: pxt.Util.lf("function"),
@@ -101988,7 +102022,7 @@ var pxt;
101988
102022
  'procedures_callnoreturn': {
101989
102023
  name: pxt.Util.lf("call the function"),
101990
102024
  tooltip: pxt.Util.lf("Call the user-defined function."),
101991
- url: 'types/function/call',
102025
+ url: '/types/function/call',
101992
102026
  category: 'functions',
101993
102027
  block: {
101994
102028
  PROCEDURES_CALLNORETURN_TITLE: pxt.Util.lf("call function")
@@ -101997,7 +102031,7 @@ var pxt;
101997
102031
  'function_return': {
101998
102032
  name: pxt.Util.lf("return a value from within a function"),
101999
102033
  tooltip: pxt.Util.lf("Return a value from within a user-defined function."),
102000
- url: 'types/function/return',
102034
+ url: '/types/function/return',
102001
102035
  category: 'functions',
102002
102036
  block: {
102003
102037
  message_with_value: pxt.Util.lf("return %1"),
@@ -102007,7 +102041,7 @@ var pxt;
102007
102041
  'function_definition': {
102008
102042
  name: pxt.Util.lf("define the function"),
102009
102043
  tooltip: pxt.Util.lf("Create a function."),
102010
- url: 'types/function/define',
102044
+ url: '/types/function/define',
102011
102045
  category: 'functions',
102012
102046
  block: {
102013
102047
  FUNCTIONS_EDIT_OPTION: pxt.Util.lf("Edit Function")
@@ -102016,7 +102050,7 @@ var pxt;
102016
102050
  'function_call': {
102017
102051
  name: pxt.Util.lf("call the function"),
102018
102052
  tooltip: pxt.Util.lf("Call the user-defined function."),
102019
- url: 'types/function/call',
102053
+ url: '/types/function/call',
102020
102054
  category: 'functions',
102021
102055
  block: {
102022
102056
  FUNCTIONS_CALL_TITLE: pxt.Util.lf("call"),
@@ -102026,7 +102060,7 @@ var pxt;
102026
102060
  'function_call_output': {
102027
102061
  name: pxt.Util.lf("call the function with a return value"),
102028
102062
  tooltip: pxt.Util.lf("Call the user-defined function with a return value."),
102029
- url: 'types/function/call',
102063
+ url: '/types/function/call',
102030
102064
  category: 'functions',
102031
102065
  block: {}
102032
102066
  }
@@ -157644,94 +157678,105 @@ ${gcards.map(gcard => `[${gcard.name}](${gcard.url})`).join(',\n')}
157644
157678
  nodeutil.writeFileSync("built/target-strings.json", nodeutil.stringify(targetStringsSorted));
157645
157679
  pxt.log(`target-strings.json built`);
157646
157680
  }
157647
- function buildSemanticUIAsync(parsed) {
157648
- const forceRedbuild = parsed && parsed.flags["force"] || false;
157649
- if (!fs.existsSync(path.join("theme", "style.less")) ||
157650
- !fs.existsSync(path.join("theme", "theme.config")))
157651
- return Promise.resolve();
157652
- let dirty = !fs.existsSync("built/web/semantic.css");
157653
- if (!dirty) {
157654
- const csstime = fs.statSync("built/web/semantic.css").mtime;
157655
- dirty = nodeutil.allFiles("theme")
157656
- .map(f => fs.statSync(f))
157657
- .some(stat => stat.mtime > csstime);
157658
- }
157659
- if (!dirty && !forceRedbuild)
157660
- return Promise.resolve();
157661
- let pkg = readJson("package.json");
157681
+ async function buildSemanticUIAsync(parsed) {
157682
+ if (!fs.existsSync(path.join("theme", "style.less")) || !fs.existsSync(path.join("theme", "theme.config"))) {
157683
+ return;
157684
+ }
157685
+ const pkg = readJson("package.json");
157686
+ const isPxtCore = pkg["name"] === "pxt-core";
157662
157687
  nodeutil.mkdirP(path.join("built", "web"));
157663
157688
  const lessPath = require.resolve('less');
157664
157689
  const lessCPath = path.join(path.dirname(lessPath), '/bin/lessc');
157665
- return nodeutil.spawnAsync({
157690
+ const lessIncludePaths = [
157691
+ "node_modules/semantic-ui-less",
157692
+ "node_modules/pxt-core/theme",
157693
+ "theme/foo/bar",
157694
+ "theme",
157695
+ "node_modules/pxt-core/react-common/styles",
157696
+ "react-common/styles"
157697
+ ].join(":");
157698
+ // Build semantic css
157699
+ await nodeutil.spawnAsync({
157666
157700
  cmd: "node",
157667
- args: [lessCPath, "theme/style.less", "built/web/semantic.css", "--include-path=node_modules/semantic-ui-less:node_modules/pxt-core/theme:theme/foo/bar"]
157668
- }).then(() => {
157669
- function linkFont(font, semCss) {
157670
- const fontFile = fs.readFileSync("node_modules/semantic-ui-less/themes/default/assets/fonts/" + font + ".woff");
157671
- const url = "url(data:application/font-woff;charset=utf-8;base64,"
157672
- + fontFile.toString("base64") + ") format('woff')";
157673
- const r = new RegExp(`src:.*url\\("fonts\/${font}\\.woff.*`, "g");
157674
- semCss = semCss.replace('src: url("fonts/' + font + '.eot");', "")
157675
- .replace(r, "src: " + url + ";");
157676
- return semCss;
157677
- }
157678
- let semCss = fs.readFileSync('built/web/semantic.css', "utf8");
157679
- semCss = linkFont("icons", semCss);
157680
- semCss = linkFont("outline-icons", semCss);
157681
- semCss = linkFont("brand-icons", semCss);
157682
- return semCss;
157683
- }).then((semCss) => {
157684
- // Append icons.css to semantic.css (custom pxt icons)
157685
- const iconsFile = (pkg["name"] == "pxt-core") ? 'built/web/icons.css' : 'node_modules/pxt-core/built/web/icons.css';
157686
- const iconsCss = fs.readFileSync(iconsFile, "utf-8");
157687
- const reactCommonFile = (pkg["name"] == "pxt-core") ? 'built/web/react-common.css' : 'node_modules/pxt-core/built/web/react-common.css';
157688
- const reactCommonCss = fs.readFileSync(reactCommonFile, "utf-8");
157689
- semCss = semCss + "\n" + iconsCss + "\n" + reactCommonCss;
157690
- nodeutil.writeFileSync('built/web/semantic.css', semCss);
157691
- }).then(() => {
157692
- // generate blockly css
157693
- if (!fs.existsSync(path.join("theme", "blockly.less")))
157694
- return Promise.resolve();
157695
- return nodeutil.spawnAsync({
157701
+ args: [
157702
+ lessCPath,
157703
+ "theme/style.less",
157704
+ "built/web/semantic.css",
157705
+ "--include-path=" + lessIncludePaths
157706
+ ]
157707
+ });
157708
+ // Inline all of our icon fonts
157709
+ let semCss = await readFileAsync('built/web/semantic.css', "utf8");
157710
+ semCss = await linkFontAsync("icons", semCss);
157711
+ semCss = await linkFontAsync("outline-icons", semCss);
157712
+ semCss = await linkFontAsync("brand-icons", semCss);
157713
+ // Append icons.css to semantic.css (custom pxt icons)
157714
+ const iconsFile = isPxtCore ? 'built/web/icons.css' : 'node_modules/pxt-core/built/web/icons.css';
157715
+ const iconsCss = await readFileAsync(iconsFile, "utf8");
157716
+ semCss = semCss + "\n" + iconsCss;
157717
+ nodeutil.writeFileSync('built/web/semantic.css', semCss);
157718
+ // Generate blockly css
157719
+ if (fs.existsSync(path.join("theme", "blockly.less"))) {
157720
+ await nodeutil.spawnAsync({
157696
157721
  cmd: "node",
157697
- args: [lessCPath, "theme/blockly.less", "built/web/blockly.css", "--include-path=node_modules/semantic-ui-less:node_modules/pxt-core/theme:theme/foo/bar"]
157698
- });
157699
- }).then(() => {
157700
- // run postcss with autoprefixer and rtlcss
157701
- pxt.debug("running postcss");
157702
- const postcss = require('postcss');
157703
- const browserList = [
157704
- "Chrome >= 38",
157705
- "Firefox >= 31",
157706
- "Edge >= 12",
157707
- "ie >= 11",
157708
- "Safari >= 9",
157709
- "Opera >= 21",
157710
- "iOS >= 9",
157711
- "ChromeAndroid >= 59",
157712
- "FirefoxAndroid >= 55"
157713
- ];
157714
- const cssnano = require('cssnano')({
157715
- zindex: false,
157716
- autoprefixer: { browsers: browserList, add: true }
157717
- });
157718
- const rtlcss = require('rtlcss');
157719
- const files = ['semantic.css', 'blockly.css'];
157720
- files.forEach(cssFile => {
157721
- fs.readFile(`built/web/${cssFile}`, "utf8", (err, css) => {
157722
- postcss([cssnano])
157723
- .process(css, { from: `built/web/${cssFile}`, to: `built/web/${cssFile}` }).then((result) => {
157724
- fs.writeFile(`built/web/${cssFile}`, result.css, (err2) => {
157725
- // process rtl css
157726
- postcss([rtlcss])
157727
- .process(result.css, { from: `built/web/${cssFile}`, to: `built/web/rtl${cssFile}` }).then((result2) => {
157728
- nodeutil.writeFileSync(`built/web/rtl${cssFile}`, result2.css, { encoding: "utf8" });
157729
- });
157730
- });
157731
- });
157732
- });
157722
+ args: [
157723
+ lessCPath,
157724
+ "theme/blockly.less",
157725
+ "built/web/blockly.css",
157726
+ "--include-path=" + lessIncludePaths
157727
+ ]
157733
157728
  });
157729
+ }
157730
+ // Generate react-common css for skillmap
157731
+ const skillmapFile = isPxtCore ? "react-common/styles/react-common-skillmap-core.less" :
157732
+ "node_modules/pxt-core/react-common/styles/react-common-skillmap.less";
157733
+ await nodeutil.spawnAsync({
157734
+ cmd: "node",
157735
+ args: [
157736
+ lessCPath,
157737
+ skillmapFile,
157738
+ "built/web/react-common-skillmap.css",
157739
+ "--include-path=" + lessIncludePaths
157740
+ ]
157734
157741
  });
157742
+ // Run postcss with autoprefixer and rtlcss
157743
+ pxt.debug("running postcss");
157744
+ const postcss = require('postcss');
157745
+ const browserList = [
157746
+ "Chrome >= 38",
157747
+ "Firefox >= 31",
157748
+ "Edge >= 12",
157749
+ "ie >= 11",
157750
+ "Safari >= 9",
157751
+ "Opera >= 21",
157752
+ "iOS >= 9",
157753
+ "ChromeAndroid >= 59",
157754
+ "FirefoxAndroid >= 55"
157755
+ ];
157756
+ const cssnano = require("cssnano")({
157757
+ zindex: false,
157758
+ autoprefixer: { browsers: browserList, add: true }
157759
+ });
157760
+ const rtlcss = require("rtlcss");
157761
+ const files = ["semantic.css", "blockly.css", "react-common-skillmap.css"];
157762
+ for (const cssFile of files) {
157763
+ const css = await readFileAsync(`built/web/${cssFile}`, "utf8");
157764
+ const processed = await postcss([cssnano])
157765
+ .process(css, { from: `built/web/${cssFile}`, to: `built/web/${cssFile}` });
157766
+ await writeFileAsync(`built/web/${cssFile}`, processed.css);
157767
+ const processedRtl = await postcss([rtlcss])
157768
+ .process(processed.css, { from: `built/web/${cssFile}`, to: `built/web/rtl${cssFile}` });
157769
+ await writeFileAsync(`built/web/rtl${cssFile}`, processedRtl.css, "utf8");
157770
+ }
157771
+ }
157772
+ async function linkFontAsync(font, semCss) {
157773
+ const fontFile = await readFileAsync("node_modules/semantic-ui-less/themes/default/assets/fonts/" + font + ".woff");
157774
+ const url = "url(data:application/font-woff;charset=utf-8;base64,"
157775
+ + fontFile.toString("base64") + ") format('woff')";
157776
+ const r = new RegExp(`src:.*url\\("fonts\/${font}\\.woff.*`, "g");
157777
+ semCss = semCss.replace('src: url("fonts/' + font + '.eot");', "")
157778
+ .replace(r, "src: " + url + ";");
157779
+ return semCss;
157735
157780
  }
157736
157781
  function buildWebStringsAsync() {
157737
157782
  if (pxt.appTarget.id != "core")
@@ -157754,7 +157799,7 @@ function buildSkillMapAsync(parsed) {
157754
157799
  nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${skillmapRoot}/public/blb`);
157755
157800
  nodeutil.cp("built/web/semantic.css", `${skillmapRoot}/public/blb`);
157756
157801
  nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${skillmapRoot}/public/blb`);
157757
- nodeutil.cp("node_modules/pxt-core/built/web/react-common.css", `${skillmapRoot}/public/blb`);
157802
+ nodeutil.cp("node_modules/pxt-core/built/web/react-common-skillmap.css", `${skillmapRoot}/public/blb`);
157758
157803
  // copy 'assets' over from docs/static
157759
157804
  nodeutil.cpR("docs/static/skillmap/assets", `${skillmapRoot}/public/assets`);
157760
157805
  if (docsPath) {
@@ -162112,7 +162157,7 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
162112
162157
  help: "build required css files",
162113
162158
  flags: {
162114
162159
  force: {
162115
- description: "force re-compile of less files"
162160
+ description: "deprecated; now on by default"
162116
162161
  }
162117
162162
  }
162118
162163
  }, buildSemanticUIAsync);