@uniformdev/cli 20.57.2-alpha.22 → 20.57.2-alpha.24

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,4 +1,4 @@
1
- import { C as CLIConfiguration, E as EntityTypes } from './index-Cs_pXOjF.mjs';
1
+ import { C as CLIConfiguration, E as EntityTypes } from './index-B-KaB0aa.mjs';
2
2
 
3
3
  type UniformConfigAllOptions = {
4
4
  /**
@@ -12,11 +12,17 @@ type EntityConfigurationBase = {
12
12
  format?: SyncFileFormat;
13
13
  disabled?: true;
14
14
  };
15
+ type EntityFilterCriteriaConfig = {
16
+ type: 'ids';
17
+ match: string[];
18
+ } | {
19
+ type: 'nameContains';
20
+ match: string;
21
+ };
15
22
  type EntityFilterInclude = {
16
23
  /** If set, only entities matching the criteria will be synced. Cannot be combined with `exclude`. */
17
24
  include: {
18
- ids?: string[];
19
- namePattern?: string;
25
+ filters: EntityFilterCriteriaConfig;
20
26
  };
21
27
  exclude?: never;
22
28
  };
@@ -24,8 +30,7 @@ type EntityFilterExclude = {
24
30
  include?: never;
25
31
  /** If set, entities matching the criteria will be excluded from sync. Cannot be combined with `include`. */
26
32
  exclude: {
27
- ids?: string[];
28
- namePattern?: string;
33
+ filters: EntityFilterCriteriaConfig;
29
34
  };
30
35
  };
31
36
  type EntityFilterNone = {
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export { C as CLIConfiguration } from './index-Cs_pXOjF.mjs';
2
+ export { C as CLIConfiguration } from './index-B-KaB0aa.mjs';
package/dist/index.mjs CHANGED
@@ -560,68 +560,169 @@ async function createArraySyncEngineDataSource({
560
560
 
561
561
  // src/sync/entityFilter.ts
562
562
  function resolveEntityFilter(entityConfig, operation) {
563
+ if (entityConfig) {
564
+ validateEntityConfig(entityConfig, operation);
565
+ }
563
566
  const directional = entityConfig?.[operation];
564
567
  const resolvedInclude = directional?.include ?? entityConfig?.include;
565
568
  const resolvedExclude = directional?.exclude ?? entityConfig?.exclude;
566
- const includeIds = resolvedInclude?.ids;
567
- const excludeIds = resolvedExclude?.ids;
568
- const includeNamePattern = resolvedInclude?.namePattern;
569
- const excludeNamePattern = resolvedExclude?.namePattern;
570
- const hasInclude = !!(includeIds?.length || includeNamePattern);
571
- const hasExclude = !!(excludeIds?.length || excludeNamePattern);
569
+ const includeFilters = resolvedInclude?.filters;
570
+ const excludeFilters = resolvedExclude?.filters;
571
+ const hasInclude = hasCriteria(includeFilters);
572
+ const hasExclude = hasCriteria(excludeFilters);
572
573
  if (hasInclude && hasExclude) {
573
574
  const includeSource = directional?.include ? `${operation}.include` : "include";
574
575
  const excludeSource = directional?.exclude ? `${operation}.exclude` : "exclude";
575
576
  throw new Error(
576
- `Entity filter for '${operation}' resolved both ${includeSource} and ${excludeSource}. Use one or the other. If a top-level filter conflicts with a per-direction filter, set the unwanted direction to { ids: [] } to clear it.`
577
+ `Entity filter for '${operation}' resolved both ${includeSource} and ${excludeSource}. Use one or the other. If a top-level filter conflicts with a per-direction filter, set the unwanted direction to { filters: { type: 'ids', match: [] } } to clear it.`
577
578
  );
578
579
  }
579
- return createEntityFilter(
580
- { ids: includeIds, namePattern: includeNamePattern },
581
- { ids: excludeIds, namePattern: excludeNamePattern }
582
- );
580
+ return createEntityFilter(includeFilters, excludeFilters);
583
581
  }
584
582
  function createEntityFilter(include, exclude) {
585
- const includeIds = Array.isArray(include) ? include : include?.ids;
586
- const excludeIds = Array.isArray(exclude) ? exclude : exclude?.ids;
587
- const includeNamePattern = Array.isArray(include) ? void 0 : include?.namePattern;
588
- const excludeNamePattern = Array.isArray(exclude) ? void 0 : exclude?.namePattern;
589
- const hasInclude = !!(includeIds?.length || includeNamePattern);
590
- const hasExclude = !!(excludeIds?.length || excludeNamePattern);
583
+ const normalizedInclude = normalizeCriteria(include);
584
+ const normalizedExclude = normalizeCriteria(exclude);
585
+ const hasInclude = hasCriteria(normalizedInclude);
586
+ const hasExclude = hasCriteria(normalizedExclude);
591
587
  if (hasInclude && hasExclude) {
592
588
  throw new Error("Entity filter cannot have both `include` and `exclude` defined. Use one or the other.");
593
589
  }
594
590
  if (!hasInclude && !hasExclude) {
595
591
  return void 0;
596
592
  }
597
- const includeRegex = includeNamePattern ? safeRegex(includeNamePattern) : void 0;
598
- const excludeRegex = excludeNamePattern ? safeRegex(excludeNamePattern) : void 0;
599
593
  if (hasInclude) {
600
- const includeSet = includeIds?.length ? new Set(includeIds) : void 0;
594
+ return buildMatcher(normalizedInclude, true);
595
+ }
596
+ return buildMatcher(normalizedExclude, false);
597
+ }
598
+ function normalizeCriteria(criteria) {
599
+ if (Array.isArray(criteria)) {
600
+ return criteria.length > 0 ? { type: "ids", match: criteria } : void 0;
601
+ }
602
+ return criteria;
603
+ }
604
+ var VALID_FILTER_TYPES = ["ids", "nameContains"];
605
+ var VALID_FILTER_FIELDS = ["include", "exclude"];
606
+ var VALID_DIRECTION_KEYS = ["pull", "push"];
607
+ var VALID_ENTITY_CONFIG_KEYS = /* @__PURE__ */ new Set([...VALID_DIRECTION_KEYS, ...VALID_FILTER_FIELDS]);
608
+ var VALID_FILTER_BLOCK_KEYS = ["filters"];
609
+ function validateEntityConfig(entityConfig, operation) {
610
+ const validKeysLabel = [...VALID_ENTITY_CONFIG_KEYS].join(", ");
611
+ for (const key of Object.keys(entityConfig)) {
612
+ if (!VALID_ENTITY_CONFIG_KEYS.has(key)) {
613
+ const suggestion = VALID_DIRECTION_KEYS.find((valid) => key.startsWith(valid));
614
+ const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
615
+ throw new Error(`Unknown entity filter key "${key}".${hint} Valid keys are: ${validKeysLabel}.`);
616
+ }
617
+ }
618
+ const directional = entityConfig[operation];
619
+ if (directional && typeof directional === "object") {
620
+ const validFilterLabel = VALID_FILTER_FIELDS.join(", ");
621
+ for (const key of Object.keys(directional)) {
622
+ if (!VALID_FILTER_FIELDS.includes(key)) {
623
+ throw new Error(
624
+ `Unknown key "${key}" in ${operation} filter config. Valid keys are: ${validFilterLabel}.`
625
+ );
626
+ }
627
+ }
628
+ }
629
+ for (const field of VALID_FILTER_FIELDS) {
630
+ validateFilterBlock(entityConfig[field], field);
631
+ }
632
+ if (directional && typeof directional === "object") {
633
+ for (const field of VALID_FILTER_FIELDS) {
634
+ validateFilterBlock(directional[field], `${operation}.${field}`);
635
+ }
636
+ }
637
+ }
638
+ function validateFilterBlock(value, label) {
639
+ if (value === void 0 || value === null) {
640
+ return;
641
+ }
642
+ if (typeof value === "string") {
643
+ throw new Error(
644
+ `"${label}" must be an object like { filters: { type: 'nameContains', match: '${value}' } }, not a plain string.`
645
+ );
646
+ }
647
+ if (Array.isArray(value)) {
648
+ throw new Error(
649
+ `"${label}" must be an object like { filters: { type: 'ids', match: [...] } }, not a plain array.`
650
+ );
651
+ }
652
+ if (typeof value !== "object") {
653
+ throw new Error(`"${label}" must be an object with a "filters" field, but got ${typeof value}.`);
654
+ }
655
+ const block = value;
656
+ if ("type" in block && "match" in block) {
657
+ throw new Error(
658
+ `"${label}" has "type" and "match" at the top level. Wrap them in a "filters" key: { filters: { type: '${block.type}', match: ... } }.`
659
+ );
660
+ }
661
+ const validBlockKeysLabel = VALID_FILTER_BLOCK_KEYS.join(", ");
662
+ for (const key of Object.keys(block)) {
663
+ if (!VALID_FILTER_BLOCK_KEYS.includes(key)) {
664
+ throw new Error(`Unknown key "${key}" in ${label}. Valid keys are: ${validBlockKeysLabel}.`);
665
+ }
666
+ }
667
+ if (block.filters !== void 0) {
668
+ validateFilterCriteria(block.filters, `${label}.filters`);
669
+ }
670
+ }
671
+ function validateFilterCriteria(value, label) {
672
+ if (value === void 0 || value === null) {
673
+ return;
674
+ }
675
+ if (typeof value !== "object" || Array.isArray(value)) {
676
+ throw new Error(
677
+ `${label} must be an object like { type: 'ids', match: [...] }, but got ${typeof value}.`
678
+ );
679
+ }
680
+ const criteria = value;
681
+ if (!criteria.type) {
682
+ throw new Error(
683
+ `${label} is missing required "type" field. Expected one of: ${VALID_FILTER_TYPES.join(", ")}.`
684
+ );
685
+ }
686
+ if (!VALID_FILTER_TYPES.includes(criteria.type)) {
687
+ throw new Error(
688
+ `${label} has unknown type "${criteria.type}". Expected one of: ${VALID_FILTER_TYPES.join(", ")}.`
689
+ );
690
+ }
691
+ if (criteria.type === "ids" && !Array.isArray(criteria.match)) {
692
+ throw new Error(
693
+ `${label} with type "ids" requires "match" to be a string array, but got ${typeof criteria.match}.`
694
+ );
695
+ }
696
+ if (criteria.type === "nameContains" && typeof criteria.match !== "string") {
697
+ throw new Error(
698
+ `${label} with type "nameContains" requires "match" to be a string, but got ${typeof criteria.match}.`
699
+ );
700
+ }
701
+ }
702
+ function hasCriteria(criteria) {
703
+ if (!criteria) {
704
+ return false;
705
+ }
706
+ if (criteria.type === "ids") {
707
+ return criteria.match.length > 0;
708
+ }
709
+ return criteria.match.length > 0;
710
+ }
711
+ function buildMatcher(criteria, isInclude) {
712
+ if (criteria.type === "ids") {
713
+ const idSet = new Set(criteria.match);
601
714
  return (obj) => {
602
715
  const ids = Array.isArray(obj.id) ? obj.id : [obj.id];
603
- const matchesIds = includeSet ? ids.some((id) => includeSet.has(id)) : true;
604
- const matchesName = includeRegex ? includeRegex.test(obj.displayName ?? "") : true;
605
- return matchesIds && matchesName;
716
+ const matches = ids.some((id) => idSet.has(id));
717
+ return isInclude ? matches : !matches;
606
718
  };
607
719
  }
608
- const excludeSet = excludeIds?.length ? new Set(excludeIds) : void 0;
720
+ const needle = criteria.match.toLowerCase();
609
721
  return (obj) => {
610
- const ids = Array.isArray(obj.id) ? obj.id : [obj.id];
611
- const matchesIds = excludeSet ? ids.some((id) => excludeSet.has(id)) : false;
612
- const matchesName = excludeRegex ? excludeRegex.test(obj.displayName ?? "") : false;
613
- return !(matchesIds || matchesName);
722
+ const matches = (obj.displayName ?? "").toLowerCase().includes(needle);
723
+ return isInclude ? matches : !matches;
614
724
  };
615
725
  }
616
- function safeRegex(pattern) {
617
- try {
618
- return new RegExp(pattern);
619
- } catch {
620
- throw new Error(
621
- `Invalid namePattern regex: "${pattern}". Provide a valid JavaScript regular expression.`
622
- );
623
- }
624
- }
625
726
 
626
727
  // src/sync/fileSyncEngineDataSource.ts
627
728
  import { red } from "colorette";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/cli",
3
- "version": "20.57.2-alpha.22+a76473d7ee",
3
+ "version": "20.57.2-alpha.24+b45bd27ec0",
4
4
  "description": "Uniform command line interface tool",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "main": "./cli.js",
@@ -28,13 +28,13 @@
28
28
  "dependencies": {
29
29
  "@inquirer/prompts": "^7.10.1",
30
30
  "@thi.ng/mime": "^2.2.23",
31
- "@uniformdev/assets": "20.57.2-alpha.22+a76473d7ee",
32
- "@uniformdev/canvas": "20.57.2-alpha.22+a76473d7ee",
33
- "@uniformdev/context": "20.57.2-alpha.22+a76473d7ee",
34
- "@uniformdev/files": "20.57.2-alpha.22+a76473d7ee",
35
- "@uniformdev/project-map": "20.57.2-alpha.22+a76473d7ee",
36
- "@uniformdev/redirect": "20.57.2-alpha.22+a76473d7ee",
37
- "@uniformdev/richtext": "20.57.2-alpha.22+a76473d7ee",
31
+ "@uniformdev/assets": "20.57.2-alpha.24+b45bd27ec0",
32
+ "@uniformdev/canvas": "20.57.2-alpha.24+b45bd27ec0",
33
+ "@uniformdev/context": "20.57.2-alpha.24+b45bd27ec0",
34
+ "@uniformdev/files": "20.57.2-alpha.24+b45bd27ec0",
35
+ "@uniformdev/project-map": "20.57.2-alpha.24+b45bd27ec0",
36
+ "@uniformdev/redirect": "20.57.2-alpha.24+b45bd27ec0",
37
+ "@uniformdev/richtext": "20.57.2-alpha.24+b45bd27ec0",
38
38
  "call-bind": "^1.0.2",
39
39
  "colorette": "2.0.20",
40
40
  "cosmiconfig": "9.0.0",
@@ -81,5 +81,5 @@
81
81
  "publishConfig": {
82
82
  "access": "public"
83
83
  },
84
- "gitHead": "a76473d7ee17e2c8745b1f240d670afb90108f36"
84
+ "gitHead": "b45bd27ec09cbc11c81b4abea2579548c5a57ed1"
85
85
  }