@creationix/rex 0.4.1 → 0.6.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.
@@ -27,7 +27,6 @@ const OPCODES = {
27
27
  mod: "md",
28
28
  neg: "ng",
29
29
  range: "rn",
30
- size: "sz",
31
30
  } as const;
32
31
 
33
32
  export type RexcContext = {
@@ -47,7 +46,7 @@ export type RexcRuntimeState = {
47
46
 
48
47
  type LoopControl = { kind: "break" | "continue"; depth: number };
49
48
 
50
- type OpcodeMarker = { __opcode: string };
49
+ type OpcodeMarker = { __opcode: string; __receiver?: unknown };
51
50
 
52
51
  function decodePrefix(text: string, start: number, end: number): number {
53
52
  let value = 0;
@@ -328,7 +327,9 @@ class CursorInterpreter {
328
327
  this.ensure(")");
329
328
 
330
329
  if (typeof callee === "object" && callee && "__opcode" in callee) {
331
- return this.applyOpcode((callee as OpcodeMarker).__opcode as string, args);
330
+ const marker = callee as OpcodeMarker;
331
+ const opArgs = marker.__receiver !== undefined ? [marker.__receiver, ...args] : args;
332
+ return this.applyOpcode(marker.__opcode as string, opArgs);
332
333
  }
333
334
  return this.navigate(callee, args);
334
335
  }
@@ -737,10 +738,26 @@ class CursorInterpreter {
737
738
  return args.length ? args[args.length - 1] : undefined;
738
739
  case OPCODES.add:
739
740
  if (args[0] === undefined || args[1] === undefined) return undefined;
740
- if (typeof args[0] === "string" || typeof args[1] === "string") {
741
- return String(args[0]) + String(args[1]);
741
+ if (Array.isArray(args[0]) && Array.isArray(args[1])) {
742
+ return [...args[0], ...args[1]];
742
743
  }
743
- return Number(args[0]) + Number(args[1]);
744
+ if (
745
+ args[0]
746
+ && args[1]
747
+ && typeof args[0] === "object"
748
+ && typeof args[1] === "object"
749
+ && !Array.isArray(args[0])
750
+ && !Array.isArray(args[1])
751
+ ) {
752
+ return { ...(args[0] as Record<string, unknown>), ...(args[1] as Record<string, unknown>) };
753
+ }
754
+ if (typeof args[0] === "string" && typeof args[1] === "string") {
755
+ return args[0] + args[1];
756
+ }
757
+ if (typeof args[0] === "number" && typeof args[1] === "number") {
758
+ return args[0] + args[1];
759
+ }
760
+ return undefined;
744
761
  case OPCODES.sub:
745
762
  if (args[0] === undefined || args[1] === undefined) return undefined;
746
763
  return Number(args[0]) - Number(args[1]);
@@ -808,12 +825,74 @@ class CursorInterpreter {
808
825
  out.push(v);
809
826
  return out;
810
827
  }
811
- case OPCODES.size: {
828
+ case "array:push": {
812
829
  const target = args[0];
813
- if (Array.isArray(target)) return target.length;
814
- if (typeof target === "string") return Array.from(target).length;
815
- if (target && typeof target === "object") return Object.keys(target as Record<string, unknown>).length;
816
- return undefined;
830
+ if (!Array.isArray(target)) return undefined;
831
+ const next = target.slice();
832
+ for (let i = 1; i < args.length; i += 1) next.push(args[i]);
833
+ return next;
834
+ }
835
+ case "array:pop": {
836
+ const target = args[0];
837
+ if (!Array.isArray(target) || target.length === 0) return undefined;
838
+ return target[target.length - 1];
839
+ }
840
+ case "array:unshift": {
841
+ const target = args[0];
842
+ if (!Array.isArray(target)) return undefined;
843
+ const next = target.slice();
844
+ for (let i = args.length - 1; i >= 1; i -= 1) next.unshift(args[i]);
845
+ return next;
846
+ }
847
+ case "array:shift": {
848
+ const target = args[0];
849
+ if (!Array.isArray(target) || target.length === 0) return undefined;
850
+ return target[0];
851
+ }
852
+ case "array:slice": {
853
+ const target = args[0];
854
+ if (!Array.isArray(target)) return undefined;
855
+ const start = args.length > 1 && args[1] !== undefined ? Number(args[1]) : undefined;
856
+ const end = args.length > 2 && args[2] !== undefined ? Number(args[2]) : undefined;
857
+ return target.slice(start, end);
858
+ }
859
+ case "array:join": {
860
+ const target = args[0];
861
+ if (!Array.isArray(target)) return undefined;
862
+ const sep = args.length > 1 && args[1] !== undefined ? String(args[1]) : ",";
863
+ return target.map((item) => String(item)).join(sep);
864
+ }
865
+ case "string:split": {
866
+ const target = args[0];
867
+ if (typeof target !== "string") return undefined;
868
+ if (args.length < 2 || args[1] === undefined) return [target];
869
+ return target.split(String(args[1]));
870
+ }
871
+ case "string:join": {
872
+ const target = args[0];
873
+ if (typeof target !== "string") return undefined;
874
+ const parts = Array.from(target);
875
+ const sep = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
876
+ return parts.join(sep);
877
+ }
878
+ case "string:slice": {
879
+ const target = args[0];
880
+ if (typeof target !== "string") return undefined;
881
+ const start = args.length > 1 && args[1] !== undefined ? Number(args[1]) : undefined;
882
+ const end = args.length > 2 && args[2] !== undefined ? Number(args[2]) : undefined;
883
+ return Array.from(target).slice(start, end).join("");
884
+ }
885
+ case "string:starts-with": {
886
+ const target = args[0];
887
+ if (typeof target !== "string") return undefined;
888
+ const prefix = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
889
+ return target.startsWith(prefix);
890
+ }
891
+ case "string:ends-with": {
892
+ const target = args[0];
893
+ if (typeof target !== "string") return undefined;
894
+ const suffix = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
895
+ return target.endsWith(suffix);
817
896
  }
818
897
  default:
819
898
  throw new Error(`Unknown opcode ${id}`);
@@ -831,14 +910,20 @@ class CursorInterpreter {
831
910
  }
832
911
 
833
912
  private readProperty(target: unknown, key: unknown): unknown {
913
+ if (typeof key === "string" && key === "size") {
914
+ if (Array.isArray(target)) return target.length;
915
+ if (typeof target === "string") return Array.from(target).length;
916
+ }
834
917
  const index = this.parseIndexKey(key);
835
918
  if (Array.isArray(target)) {
836
- if (index === undefined) return undefined;
837
- return target[index];
919
+ if (index !== undefined) return target[index];
920
+ if (typeof key === "string") return this.resolveArrayMethod(target, key);
921
+ return undefined;
838
922
  }
839
923
  if (typeof target === "string") {
840
- if (index === undefined) return undefined;
841
- return Array.from(target)[index];
924
+ if (index !== undefined) return Array.from(target)[index];
925
+ if (typeof key === "string") return this.resolveStringMethod(target, key);
926
+ return undefined;
842
927
  }
843
928
  if (this.isPlainObject(target)) {
844
929
  const prop = String(key);
@@ -848,6 +933,42 @@ class CursorInterpreter {
848
933
  return undefined;
849
934
  }
850
935
 
936
+ private resolveArrayMethod(target: unknown[], key: string): OpcodeMarker | undefined {
937
+ switch (key) {
938
+ case "push":
939
+ return { __opcode: "array:push", __receiver: target };
940
+ case "pop":
941
+ return { __opcode: "array:pop", __receiver: target };
942
+ case "unshift":
943
+ return { __opcode: "array:unshift", __receiver: target };
944
+ case "shift":
945
+ return { __opcode: "array:shift", __receiver: target };
946
+ case "slice":
947
+ return { __opcode: "array:slice", __receiver: target };
948
+ case "join":
949
+ return { __opcode: "array:join", __receiver: target };
950
+ default:
951
+ return undefined;
952
+ }
953
+ }
954
+
955
+ private resolveStringMethod(target: string, key: string): OpcodeMarker | undefined {
956
+ switch (key) {
957
+ case "split":
958
+ return { __opcode: "string:split", __receiver: target };
959
+ case "join":
960
+ return { __opcode: "string:join", __receiver: target };
961
+ case "slice":
962
+ return { __opcode: "string:slice", __receiver: target };
963
+ case "starts-with":
964
+ return { __opcode: "string:starts-with", __receiver: target };
965
+ case "ends-with":
966
+ return { __opcode: "string:ends-with", __receiver: target };
967
+ default:
968
+ return undefined;
969
+ }
970
+ }
971
+
851
972
  private canWriteProperty(target: unknown, key: unknown): { kind: "array"; index: number } | { kind: "object" } | undefined {
852
973
  const index = this.parseIndexKey(key);
853
974
  if (Array.isArray(target)) {