@stylexjs/babel-plugin 0.18.1 → 0.18.2

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.
@@ -1,6 +1,6 @@
1
1
  import { packages } from '@babel/standalone';
2
2
  import parser from 'postcss-value-parser';
3
- import { legacyMerge, props } from '@stylexjs/stylex';
3
+ import { legacyMerge, attrs, props } from '@stylexjs/stylex';
4
4
 
5
5
  const {
6
6
  arrayExpression, arrowFunctionExpression, binaryExpression, booleanLiteral,
@@ -12,7 +12,7 @@ const {
12
12
  isNumericLiteral, isObjectExpression, isObjectProperty, isPrivateName,
13
13
  isSpreadElement, isStringLiteral, isTemplateLiteral, isUnaryExpression,
14
14
  isUpdateExpression, isValidIdentifier, isVariableDeclaration, jsxAttribute,
15
- jsxIdentifier, memberExpression, nullLiteral, numericLiteral, objectExpression,
15
+ jsxIdentifier, jsxSpreadAttribute, memberExpression, nullLiteral, numericLiteral, objectExpression,
16
16
  objectProperty, stringLiteral, unaryExpression, variableDeclaration, variableDeclarator
17
17
  } = packages.types;
18
18
 
@@ -55,6 +55,7 @@ var types = /*#__PURE__*/Object.freeze({
55
55
  isVariableDeclaration: isVariableDeclaration,
56
56
  jsxAttribute: jsxAttribute,
57
57
  jsxIdentifier: jsxIdentifier,
58
+ jsxSpreadAttribute: jsxSpreadAttribute,
58
59
  memberExpression: memberExpression,
59
60
  nullLiteral: nullLiteral,
60
61
  numericLiteral: numericLiteral,
@@ -1913,6 +1914,9 @@ function readImportDeclarations(path, state) {
1913
1914
  if (importedName === 'props') {
1914
1915
  state.stylexPropsImport.add(localName);
1915
1916
  }
1917
+ if (importedName === 'attrs') {
1918
+ state.stylexAttrsImport.add(localName);
1919
+ }
1916
1920
  if (importedName === 'keyframes') {
1917
1921
  state.stylexKeyframesImport.add(localName);
1918
1922
  }
@@ -1982,6 +1986,9 @@ function readRequires(path, state) {
1982
1986
  if (prop.key.name === 'props') {
1983
1987
  state.stylexPropsImport.add(value.name);
1984
1988
  }
1989
+ if (prop.key.name === 'attrs') {
1990
+ state.stylexAttrsImport.add(value.name);
1991
+ }
1985
1992
  if (prop.key.name === 'keyframes') {
1986
1993
  state.stylexKeyframesImport.add(value.name);
1987
1994
  }
@@ -8696,15 +8703,17 @@ class ConditionalStyle {
8696
8703
  }
8697
8704
  }
8698
8705
  function skipStylexPropsChildren(path, state) {
8699
- if (!isCalleeIdentifier(path, state) && !isCalleeMemberExpression(path, state)) {
8706
+ if (getPropsLikeCall(path, state) == null) {
8700
8707
  return;
8701
8708
  }
8702
8709
  path.skip();
8703
8710
  }
8704
8711
  function transformStylexProps(path, state) {
8705
- if (!isCalleeIdentifier(path, state) && !isCalleeMemberExpression(path, state)) {
8712
+ const propsLikeCall = getPropsLikeCall(path, state);
8713
+ if (propsLikeCall == null) {
8706
8714
  return;
8707
8715
  }
8716
+ const propsLikeFn = propsLikeCall === 'attrs' ? attrs : props;
8708
8717
  let bailOut = false;
8709
8718
  let conditional = 0;
8710
8719
  const argsPath = path.get('arguments').flatMap(argPath => argPath.isArrayExpression() ? argPath.get('elements') : [argPath]);
@@ -8844,7 +8853,7 @@ function transformStylexProps(path, state) {
8844
8853
  }
8845
8854
  } else {
8846
8855
  path.skip();
8847
- const stringExpression = makeStringExpression(resolvedArgs);
8856
+ const stringExpression = makeStringExpression(resolvedArgs, propsLikeFn);
8848
8857
  if (path.parentPath.node.type === 'JSXSpreadAttribute') {
8849
8858
  if (isObjectExpression(stringExpression) && stringExpression.properties.length > 0 && stringExpression.properties.every(prop => isObjectProperty(prop) && (isIdentifier(prop.key) || isStringLiteral(prop.key)) && !prop.computed)) {
8850
8859
  const jsxAttributes = stringExpression.properties.filter(prop => isObjectProperty(prop)).map(prop => {
@@ -8908,10 +8917,10 @@ function parseNullableStyle(path, state, evaluatePathFnConfig) {
8908
8917
  }
8909
8918
  return 'other';
8910
8919
  }
8911
- function makeStringExpression(values) {
8920
+ function makeStringExpression(values, propsLikeFn) {
8912
8921
  const conditions = values.filter(v => v instanceof ConditionalStyle).map(v => v.test);
8913
8922
  if (conditions.length === 0) {
8914
- const result = props(values);
8923
+ const result = propsLikeFn(values);
8915
8924
  return convertObjectToAST(result);
8916
8925
  }
8917
8926
  const conditionPermutations = genConditionPermutations(conditions.length);
@@ -8929,7 +8938,7 @@ function makeStringExpression(values) {
8929
8938
  }
8930
8939
  });
8931
8940
  const key = permutation.reduce((soFar, bool) => soFar << 1 | (bool ? 1 : 0), 0);
8932
- return objectProperty(numericLiteral(key), convertObjectToAST(props(args)));
8941
+ return objectProperty(numericLiteral(key), convertObjectToAST(propsLikeFn(args)));
8933
8942
  });
8934
8943
  const objExpressions = objectExpression(objEntries);
8935
8944
  const conditionsToKey = genBitwiseOrOfConditions(conditions);
@@ -8955,17 +8964,26 @@ function genBitwiseOrOfConditions(conditions) {
8955
8964
  return binaryExpression('|', acc, expr);
8956
8965
  });
8957
8966
  }
8958
- function isCalleeIdentifier(path, state) {
8967
+ function getPropsLikeCall(path, state) {
8959
8968
  const {
8960
8969
  node
8961
8970
  } = path;
8962
- return node != null && node.callee != null && node.callee.type === 'Identifier' && state.stylexPropsImport.has(node.callee.name);
8963
- }
8964
- function isCalleeMemberExpression(path, state) {
8965
- const {
8966
- node
8967
- } = path;
8968
- return node != null && node.callee != null && node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'props' && state.stylexImport.has(node.callee.object.name);
8971
+ const callee = node?.callee;
8972
+ if (node != null && callee != null && callee.type === 'Identifier' && state.stylexPropsImport.has(callee.name)) {
8973
+ return 'props';
8974
+ }
8975
+ if (node != null && callee != null && callee.type === 'Identifier' && state.stylexAttrsImport.has(callee.name)) {
8976
+ return 'attrs';
8977
+ }
8978
+ if (node != null && callee != null && callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.property.type === 'Identifier' && state.stylexImport.has(callee.object.name)) {
8979
+ if (callee.property.name === 'props') {
8980
+ return 'props';
8981
+ }
8982
+ if (callee.property.name === 'attrs') {
8983
+ return 'attrs';
8984
+ }
8985
+ }
8986
+ return null;
8969
8987
  }
8970
8988
 
8971
8989
  function styleXViewTransitionClass(styles, options = defaultOptions) {
@@ -9331,7 +9349,7 @@ function styleXTransform() {
9331
9349
  if (value.isJSXEmptyExpression()) {
9332
9350
  continue;
9333
9351
  }
9334
- attr.replaceWith(undefined(callExpression(memberExpression(identifier('stylex'), identifier('props')), [value.node])));
9352
+ attr.replaceWith(jsxSpreadAttribute(callExpression(memberExpression(identifier('stylex'), identifier('props')), [value.node])));
9335
9353
  break;
9336
9354
  }
9337
9355
  },
@@ -9385,14 +9403,19 @@ function getLogicalFloatVars(rules) {
9385
9403
  ` : '';
9386
9404
  }
9387
9405
  function processStylexRules(rules, config) {
9406
+ const rawConfig = typeof config === 'boolean' ? {
9407
+ useLayers: config
9408
+ } : config ?? {};
9388
9409
  const {
9389
- useLayers = false,
9390
9410
  enableLTRRTLComments = false,
9391
9411
  legacyDisableLayers = false,
9392
9412
  useLegacyClassnamesSort = false
9393
- } = typeof config === 'boolean' ? {
9394
- useLayers: config
9395
- } : config ?? {};
9413
+ } = rawConfig;
9414
+ const rawUseLayers = rawConfig.useLayers ?? false;
9415
+ const useLayers = rawUseLayers !== false;
9416
+ const layersBefore = typeof rawUseLayers === 'object' ? rawUseLayers.before ?? [] : [];
9417
+ const layersAfter = typeof rawUseLayers === 'object' ? rawUseLayers.after ?? [] : [];
9418
+ const layerPrefix = typeof rawUseLayers === 'object' ? rawUseLayers.prefix ?? '' : '';
9396
9419
  if (rules.length === 0) {
9397
9420
  return '';
9398
9421
  }
@@ -9439,16 +9462,11 @@ function processStylexRules(rules, config) {
9439
9462
  if (useLegacyClassnamesSort) {
9440
9463
  return classname1.localeCompare(classname2);
9441
9464
  } else {
9442
- if (rule1.startsWith('@') && !rule2.startsWith('@')) {
9443
- const query1 = rule1.slice(0, rule1.indexOf('{'));
9444
- const query2 = rule2.slice(0, rule2.indexOf('{'));
9445
- if (query1 !== query2) {
9446
- return query1.localeCompare(query2);
9447
- }
9448
- }
9449
9465
  const property1 = rule1.slice(rule1.lastIndexOf('{'));
9450
9466
  const property2 = rule2.slice(rule2.lastIndexOf('{'));
9451
- return property1.localeCompare(property2);
9467
+ const propertyComparison = property1.localeCompare(property2);
9468
+ if (propertyComparison !== 0) return propertyComparison;
9469
+ return rule1.localeCompare(rule2);
9452
9470
  }
9453
9471
  });
9454
9472
  let lastKPri = -1;
@@ -9482,7 +9500,8 @@ function processStylexRules(rules, config) {
9482
9500
  return acc;
9483
9501
  }, []);
9484
9502
  const logicalFloatVars = getLogicalFloatVars(nonConstantRules);
9485
- const header = useLayers ? '\n@layer ' + grouped.map((_, index) => `priority${index + 1}`).join(', ') + ';\n' : '';
9503
+ const layerName = index => layerPrefix ? `${layerPrefix}.priority${index + 1}` : `priority${index + 1}`;
9504
+ const header = useLayers ? '\n@layer ' + [...layersBefore, ...grouped.map((_, index) => layerName(index)), ...layersAfter].join(', ') + ';\n' : '';
9486
9505
  const collectedCSS = grouped.map((group, index) => {
9487
9506
  const pri = group[0][2];
9488
9507
  const collectedCSS = Array.from(new Map(group.map(([a, b]) => [a, b])).values()).flatMap(rule => {
@@ -9502,7 +9521,7 @@ function processStylexRules(rules, config) {
9502
9521
  }
9503
9522
  return rtlRule ? enableLTRRTLComments ? [`/* @ltr begin */${ltrRule}/* @ltr end */`, `/* @rtl begin */${rtlRule}/* @rtl end */`] : [addAncestorSelector(ltrRule, "html:not([dir='rtl'])"), addAncestorSelector(rtlRule, "html[dir='rtl']")] : [ltrRule];
9504
9523
  }).join('\n');
9505
- return useLayers && pri > 0 ? `@layer priority${index + 1}{\n${collectedCSS}\n}` : collectedCSS;
9524
+ return useLayers && pri > 0 ? `@layer ${layerName(index)}{\n${collectedCSS}\n}` : collectedCSS;
9506
9525
  }).join('\n');
9507
9526
  return logicalFloatVars + header + collectedCSS;
9508
9527
  }
package/lib/index.d.ts CHANGED
@@ -44,7 +44,13 @@ declare function processStylexRules(
44
44
  config?:
45
45
  | boolean
46
46
  | {
47
- useLayers?: boolean;
47
+ useLayers?:
48
+ | boolean
49
+ | {
50
+ before?: ReadonlyArray<string>;
51
+ after?: ReadonlyArray<string>;
52
+ prefix?: string;
53
+ };
48
54
  enableLTRRTLComments?: boolean;
49
55
  legacyDisableLayers?: boolean;
50
56
  },
package/lib/index.js CHANGED
@@ -799,6 +799,9 @@ function readImportDeclarations(path, state) {
799
799
  if (importedName === 'props') {
800
800
  state.stylexPropsImport.add(localName);
801
801
  }
802
+ if (importedName === 'attrs') {
803
+ state.stylexAttrsImport.add(localName);
804
+ }
802
805
  if (importedName === 'keyframes') {
803
806
  state.stylexKeyframesImport.add(localName);
804
807
  }
@@ -868,6 +871,9 @@ function readRequires(path, state) {
868
871
  if (prop.key.name === 'props') {
869
872
  state.stylexPropsImport.add(value.name);
870
873
  }
874
+ if (prop.key.name === 'attrs') {
875
+ state.stylexAttrsImport.add(value.name);
876
+ }
871
877
  if (prop.key.name === 'keyframes') {
872
878
  state.stylexKeyframesImport.add(value.name);
873
879
  }
@@ -7578,15 +7584,17 @@ class ConditionalStyle {
7578
7584
  }
7579
7585
  }
7580
7586
  function skipStylexPropsChildren(path, state) {
7581
- if (!isCalleeIdentifier(path, state) && !isCalleeMemberExpression(path, state)) {
7587
+ if (getPropsLikeCall(path, state) == null) {
7582
7588
  return;
7583
7589
  }
7584
7590
  path.skip();
7585
7591
  }
7586
7592
  function transformStylexProps(path, state) {
7587
- if (!isCalleeIdentifier(path, state) && !isCalleeMemberExpression(path, state)) {
7593
+ const propsLikeCall = getPropsLikeCall(path, state);
7594
+ if (propsLikeCall == null) {
7588
7595
  return;
7589
7596
  }
7597
+ const propsLikeFn = propsLikeCall === 'attrs' ? stylex.attrs : stylex.props;
7590
7598
  let bailOut = false;
7591
7599
  let conditional = 0;
7592
7600
  const argsPath = path.get('arguments').flatMap(argPath => argPath.isArrayExpression() ? argPath.get('elements') : [argPath]);
@@ -7726,7 +7734,7 @@ function transformStylexProps(path, state) {
7726
7734
  }
7727
7735
  } else {
7728
7736
  path.skip();
7729
- const stringExpression = makeStringExpression(resolvedArgs);
7737
+ const stringExpression = makeStringExpression(resolvedArgs, propsLikeFn);
7730
7738
  if (path.parentPath.node.type === 'JSXSpreadAttribute') {
7731
7739
  if (t__namespace.isObjectExpression(stringExpression) && stringExpression.properties.length > 0 && stringExpression.properties.every(prop => t__namespace.isObjectProperty(prop) && (t__namespace.isIdentifier(prop.key) || t__namespace.isStringLiteral(prop.key)) && !prop.computed)) {
7732
7740
  const jsxAttributes = stringExpression.properties.filter(prop => t__namespace.isObjectProperty(prop)).map(prop => {
@@ -7790,10 +7798,10 @@ function parseNullableStyle(path, state, evaluatePathFnConfig) {
7790
7798
  }
7791
7799
  return 'other';
7792
7800
  }
7793
- function makeStringExpression(values) {
7801
+ function makeStringExpression(values, propsLikeFn) {
7794
7802
  const conditions = values.filter(v => v instanceof ConditionalStyle).map(v => v.test);
7795
7803
  if (conditions.length === 0) {
7796
- const result = stylex.props(values);
7804
+ const result = propsLikeFn(values);
7797
7805
  return convertObjectToAST(result);
7798
7806
  }
7799
7807
  const conditionPermutations = genConditionPermutations(conditions.length);
@@ -7811,7 +7819,7 @@ function makeStringExpression(values) {
7811
7819
  }
7812
7820
  });
7813
7821
  const key = permutation.reduce((soFar, bool) => soFar << 1 | (bool ? 1 : 0), 0);
7814
- return t__namespace.objectProperty(t__namespace.numericLiteral(key), convertObjectToAST(stylex.props(args)));
7822
+ return t__namespace.objectProperty(t__namespace.numericLiteral(key), convertObjectToAST(propsLikeFn(args)));
7815
7823
  });
7816
7824
  const objExpressions = t__namespace.objectExpression(objEntries);
7817
7825
  const conditionsToKey = genBitwiseOrOfConditions(conditions);
@@ -7837,17 +7845,26 @@ function genBitwiseOrOfConditions(conditions) {
7837
7845
  return t__namespace.binaryExpression('|', acc, expr);
7838
7846
  });
7839
7847
  }
7840
- function isCalleeIdentifier(path, state) {
7848
+ function getPropsLikeCall(path, state) {
7841
7849
  const {
7842
7850
  node
7843
7851
  } = path;
7844
- return node != null && node.callee != null && node.callee.type === 'Identifier' && state.stylexPropsImport.has(node.callee.name);
7845
- }
7846
- function isCalleeMemberExpression(path, state) {
7847
- const {
7848
- node
7849
- } = path;
7850
- return node != null && node.callee != null && node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'props' && state.stylexImport.has(node.callee.object.name);
7852
+ const callee = node?.callee;
7853
+ if (node != null && callee != null && callee.type === 'Identifier' && state.stylexPropsImport.has(callee.name)) {
7854
+ return 'props';
7855
+ }
7856
+ if (node != null && callee != null && callee.type === 'Identifier' && state.stylexAttrsImport.has(callee.name)) {
7857
+ return 'attrs';
7858
+ }
7859
+ if (node != null && callee != null && callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.property.type === 'Identifier' && state.stylexImport.has(callee.object.name)) {
7860
+ if (callee.property.name === 'props') {
7861
+ return 'props';
7862
+ }
7863
+ if (callee.property.name === 'attrs') {
7864
+ return 'attrs';
7865
+ }
7866
+ }
7867
+ return null;
7851
7868
  }
7852
7869
 
7853
7870
  function styleXViewTransitionClass(styles, options = defaultOptions) {
@@ -8267,14 +8284,19 @@ function getLogicalFloatVars(rules) {
8267
8284
  ` : '';
8268
8285
  }
8269
8286
  function processStylexRules(rules, config) {
8287
+ const rawConfig = typeof config === 'boolean' ? {
8288
+ useLayers: config
8289
+ } : config ?? {};
8270
8290
  const {
8271
- useLayers = false,
8272
8291
  enableLTRRTLComments = false,
8273
8292
  legacyDisableLayers = false,
8274
8293
  useLegacyClassnamesSort = false
8275
- } = typeof config === 'boolean' ? {
8276
- useLayers: config
8277
- } : config ?? {};
8294
+ } = rawConfig;
8295
+ const rawUseLayers = rawConfig.useLayers ?? false;
8296
+ const useLayers = rawUseLayers !== false;
8297
+ const layersBefore = typeof rawUseLayers === 'object' ? rawUseLayers.before ?? [] : [];
8298
+ const layersAfter = typeof rawUseLayers === 'object' ? rawUseLayers.after ?? [] : [];
8299
+ const layerPrefix = typeof rawUseLayers === 'object' ? rawUseLayers.prefix ?? '' : '';
8278
8300
  if (rules.length === 0) {
8279
8301
  return '';
8280
8302
  }
@@ -8321,16 +8343,11 @@ function processStylexRules(rules, config) {
8321
8343
  if (useLegacyClassnamesSort) {
8322
8344
  return classname1.localeCompare(classname2);
8323
8345
  } else {
8324
- if (rule1.startsWith('@') && !rule2.startsWith('@')) {
8325
- const query1 = rule1.slice(0, rule1.indexOf('{'));
8326
- const query2 = rule2.slice(0, rule2.indexOf('{'));
8327
- if (query1 !== query2) {
8328
- return query1.localeCompare(query2);
8329
- }
8330
- }
8331
8346
  const property1 = rule1.slice(rule1.lastIndexOf('{'));
8332
8347
  const property2 = rule2.slice(rule2.lastIndexOf('{'));
8333
- return property1.localeCompare(property2);
8348
+ const propertyComparison = property1.localeCompare(property2);
8349
+ if (propertyComparison !== 0) return propertyComparison;
8350
+ return rule1.localeCompare(rule2);
8334
8351
  }
8335
8352
  });
8336
8353
  let lastKPri = -1;
@@ -8364,7 +8381,8 @@ function processStylexRules(rules, config) {
8364
8381
  return acc;
8365
8382
  }, []);
8366
8383
  const logicalFloatVars = getLogicalFloatVars(nonConstantRules);
8367
- const header = useLayers ? '\n@layer ' + grouped.map((_, index) => `priority${index + 1}`).join(', ') + ';\n' : '';
8384
+ const layerName = index => layerPrefix ? `${layerPrefix}.priority${index + 1}` : `priority${index + 1}`;
8385
+ const header = useLayers ? '\n@layer ' + [...layersBefore, ...grouped.map((_, index) => layerName(index)), ...layersAfter].join(', ') + ';\n' : '';
8368
8386
  const collectedCSS = grouped.map((group, index) => {
8369
8387
  const pri = group[0][2];
8370
8388
  const collectedCSS = Array.from(new Map(group.map(([a, b]) => [a, b])).values()).flatMap(rule => {
@@ -8384,7 +8402,7 @@ function processStylexRules(rules, config) {
8384
8402
  }
8385
8403
  return rtlRule ? enableLTRRTLComments ? [`/* @ltr begin */${ltrRule}/* @ltr end */`, `/* @rtl begin */${rtlRule}/* @rtl end */`] : [addAncestorSelector(ltrRule, "html:not([dir='rtl'])"), addAncestorSelector(rtlRule, "html[dir='rtl']")] : [ltrRule];
8386
8404
  }).join('\n');
8387
- return useLayers && pri > 0 ? `@layer priority${index + 1}{\n${collectedCSS}\n}` : collectedCSS;
8405
+ return useLayers && pri > 0 ? `@layer ${layerName(index)}{\n${collectedCSS}\n}` : collectedCSS;
8388
8406
  }).join('\n');
8389
8407
  return logicalFloatVars + header + collectedCSS;
8390
8408
  }
package/lib/index.js.flow CHANGED
@@ -51,7 +51,13 @@ declare function processStylexRules(
51
51
  config?:
52
52
  | boolean
53
53
  | {
54
- useLayers?: boolean,
54
+ useLayers?:
55
+ | boolean
56
+ | $ReadOnly<{
57
+ before?: $ReadOnlyArray<string>,
58
+ after?: $ReadOnlyArray<string>,
59
+ prefix?: string,
60
+ }>,
55
61
  enableLTRRTLComments?: boolean,
56
62
  legacyDisableLayers?: boolean,
57
63
  useLegacyClassnamesSort?: boolean,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stylexjs/babel-plugin",
3
- "version": "0.18.1",
3
+ "version": "0.18.2",
4
4
  "description": "StyleX babel plugin.",
5
5
  "main": "lib/index.js",
6
6
  "browser": "lib/index.browser.js",
@@ -23,8 +23,8 @@
23
23
  "@babel/traverse": "^7.26.8",
24
24
  "@babel/types": "^7.26.8",
25
25
  "@dual-bundle/import-meta-resolve": "^4.1.0",
26
- "@stylexjs/shared": "0.18.1",
27
- "@stylexjs/stylex": "0.18.1",
26
+ "@stylexjs/shared": "0.18.2",
27
+ "@stylexjs/stylex": "0.18.2",
28
28
  "postcss-value-parser": "^4.1.0"
29
29
  },
30
30
  "devDependencies": {
@@ -37,7 +37,7 @@
37
37
  "babel-plugin-syntax-hermes-parser": "^0.32.1",
38
38
  "path-browserify": "^1.0.1",
39
39
  "rollup": "^4.59.0",
40
- "scripts": "0.18.1"
40
+ "scripts": "0.18.2"
41
41
  },
42
42
  "files": [
43
43
  "flow_modules/*",