@ronin/compiler 0.17.5 → 0.17.6-leo-ron-1099-experimental-390

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 (2) hide show
  1. package/dist/index.js +456 -451
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23,12 +23,6 @@ var RAW_FIELD_TYPES = ["string", "number", "boolean"];
23
23
  var CURRENT_TIME_EXPRESSION = {
24
24
  [QUERY_SYMBOLS.EXPRESSION]: `strftime('%Y-%m-%dT%H:%M:%f', 'now') || 'Z'`
25
25
  };
26
- var ID_EXPRESSION = (idPrefix) => ({
27
- // Since default values in SQLite cannot rely on other columns, we unfortunately
28
- // cannot rely on the `idPrefix` column here. Instead, we need to inject it directly
29
- // into the expression as a static string.
30
- [QUERY_SYMBOLS.EXPRESSION]: `'${idPrefix}_' || lower(substr(hex(randomblob(12)), 1, 16))`
31
- });
32
26
  var MOUNTING_PATH_SUFFIX = /(.*?)(\{(\d+)\})?$/;
33
27
  var composeMountingPath = (single, key, mountingPath) => {
34
28
  if (key === "ronin_root") {
@@ -465,72 +459,457 @@ var handleSelecting = (models, model, statementParams, single, instructions, opt
465
459
  return { columns: columns.join(", "), isJoining, selectedFields };
466
460
  };
467
461
 
468
- // src/instructions/to.ts
469
- var handleTo = (models, model, statementParams, queryType, dependencyStatements, instructions, options) => {
470
- const { with: withInstruction, to: toInstruction } = instructions;
471
- const defaultFields = {};
472
- const inlineDefaultInsertionFields = queryType === "add" && options?.inlineDefaults;
473
- if (inlineDefaultInsertionFields) {
474
- defaultFields.id = toInstruction.id || ID_EXPRESSION(model.idPrefix);
462
+ // node_modules/title/dist/esm/lower-case.js
463
+ var conjunctions = [
464
+ "for",
465
+ "and",
466
+ "nor",
467
+ "but",
468
+ "or",
469
+ "yet",
470
+ "so"
471
+ ];
472
+ var articles = [
473
+ "a",
474
+ "an",
475
+ "the"
476
+ ];
477
+ var prepositions = [
478
+ "aboard",
479
+ "about",
480
+ "above",
481
+ "across",
482
+ "after",
483
+ "against",
484
+ "along",
485
+ "amid",
486
+ "among",
487
+ "anti",
488
+ "around",
489
+ "as",
490
+ "at",
491
+ "before",
492
+ "behind",
493
+ "below",
494
+ "beneath",
495
+ "beside",
496
+ "besides",
497
+ "between",
498
+ "beyond",
499
+ "but",
500
+ "by",
501
+ "concerning",
502
+ "considering",
503
+ "despite",
504
+ "down",
505
+ "during",
506
+ "except",
507
+ "excepting",
508
+ "excluding",
509
+ "following",
510
+ "for",
511
+ "from",
512
+ "in",
513
+ "inside",
514
+ "into",
515
+ "like",
516
+ "minus",
517
+ "near",
518
+ "of",
519
+ "off",
520
+ "on",
521
+ "onto",
522
+ "opposite",
523
+ "over",
524
+ "past",
525
+ "per",
526
+ "plus",
527
+ "regarding",
528
+ "round",
529
+ "save",
530
+ "since",
531
+ "than",
532
+ "through",
533
+ "to",
534
+ "toward",
535
+ "towards",
536
+ "under",
537
+ "underneath",
538
+ "unlike",
539
+ "until",
540
+ "up",
541
+ "upon",
542
+ "versus",
543
+ "via",
544
+ "with",
545
+ "within",
546
+ "without"
547
+ ];
548
+ var lowerCase = /* @__PURE__ */ new Set([
549
+ ...conjunctions,
550
+ ...articles,
551
+ ...prepositions
552
+ ]);
553
+
554
+ // node_modules/title/dist/esm/specials.js
555
+ var specials = [
556
+ "ZEIT",
557
+ "ZEIT Inc.",
558
+ "Vercel",
559
+ "Vercel Inc.",
560
+ "CLI",
561
+ "API",
562
+ "HTTP",
563
+ "HTTPS",
564
+ "JSX",
565
+ "DNS",
566
+ "URL",
567
+ "now.sh",
568
+ "now.json",
569
+ "vercel.app",
570
+ "vercel.json",
571
+ "CI",
572
+ "CD",
573
+ "CDN",
574
+ "package.json",
575
+ "package.lock",
576
+ "yarn.lock",
577
+ "GitHub",
578
+ "GitLab",
579
+ "CSS",
580
+ "Sass",
581
+ "JS",
582
+ "JavaScript",
583
+ "TypeScript",
584
+ "HTML",
585
+ "WordPress",
586
+ "Next.js",
587
+ "Node.js",
588
+ "Webpack",
589
+ "Docker",
590
+ "Bash",
591
+ "Kubernetes",
592
+ "SWR",
593
+ "TinaCMS",
594
+ "UI",
595
+ "UX",
596
+ "TS",
597
+ "TSX",
598
+ "iPhone",
599
+ "iPad",
600
+ "watchOS",
601
+ "iOS",
602
+ "iPadOS",
603
+ "macOS",
604
+ "PHP",
605
+ "composer.json",
606
+ "composer.lock",
607
+ "CMS",
608
+ "SQL",
609
+ "C",
610
+ "C#",
611
+ "GraphQL",
612
+ "GraphiQL",
613
+ "JWT",
614
+ "JWTs"
615
+ ];
616
+
617
+ // node_modules/title/dist/esm/index.js
618
+ var word = `[^\\s'\u2019\\(\\)!?;:"-]`;
619
+ var regex = new RegExp(`(?:(?:(\\s?(?:^|[.\\(\\)!?;:"-])\\s*)(${word}))|(${word}))(${word}*[\u2019']*${word}*)`, "g");
620
+ var convertToRegExp = (specials2) => specials2.map((s) => [new RegExp(`\\b${s}\\b`, "gi"), s]);
621
+ function parseMatch(match) {
622
+ const firstCharacter = match[0];
623
+ if (/\s/.test(firstCharacter)) {
624
+ return match.slice(1);
475
625
  }
476
- if (queryType === "add" || queryType === "set" || toInstruction.ronin) {
477
- const defaults = {
478
- // If records are being created, set their creation time.
479
- ...inlineDefaultInsertionFields ? { createdAt: CURRENT_TIME_EXPRESSION } : {},
480
- // If records are being updated, bump their update time.
481
- ...queryType === "set" || inlineDefaultInsertionFields ? { updatedAt: CURRENT_TIME_EXPRESSION } : {},
482
- // Allow for overwriting the default values provided above.
483
- ...toInstruction.ronin
484
- };
485
- if (Object.keys(defaults).length > 0) defaultFields.ronin = defaults;
626
+ if (/[\(\)]/.test(firstCharacter)) {
627
+ return null;
486
628
  }
487
- const symbol = getQuerySymbol(toInstruction);
488
- if (symbol?.type === "query") {
489
- const { queryModel: subQueryModelSlug, queryInstructions: subQueryInstructions } = splitQuery(symbol.value);
490
- const subQueryModel = getModelBySlug(models, subQueryModelSlug);
491
- const subQuerySelectedFields = subQueryInstructions?.selecting;
492
- const subQueryIncludedFields = subQueryInstructions?.including;
493
- const subQueryFields = [
494
- ...filterSelectedFields(subQueryModel, subQuerySelectedFields).map(
495
- (field) => field.slug
496
- ),
497
- ...subQueryIncludedFields ? Object.keys(
498
- flatten(subQueryIncludedFields || {})
499
- ) : []
500
- ];
501
- for (const field of subQueryFields || []) {
502
- getFieldFromModel(model, field, { instructionName: "to" });
629
+ return match;
630
+ }
631
+ var src_default = (str, options = {}) => {
632
+ str = str.toLowerCase().replace(regex, (m, lead = "", forced, lower, rest, offset, string) => {
633
+ const isLastWord = m.length + offset >= string.length;
634
+ const parsedMatch = parseMatch(m);
635
+ if (!parsedMatch) {
636
+ return m;
503
637
  }
504
- let statement2 = "";
505
- if (subQuerySelectedFields) {
506
- const columns = subQueryFields.map((field) => {
507
- return getFieldFromModel(model, field, { instructionName: "to" }).fieldSelector;
508
- });
509
- statement2 = `(${columns.join(", ")}) `;
638
+ if (!forced) {
639
+ const fullLower = lower + rest;
640
+ if (lowerCase.has(fullLower) && !isLastWord) {
641
+ return parsedMatch;
642
+ }
510
643
  }
511
- statement2 += compileQueryInput(symbol.value, models, statementParams, {
512
- // biome-ignore lint/complexity/useSimplifiedLogicExpression: This is needed.
513
- inlineDefaults: options?.inlineDefaults || false
514
- }).main.statement;
515
- return statement2;
644
+ return lead + (lower || forced).toUpperCase() + rest;
645
+ });
646
+ const customSpecials = options.special || [];
647
+ const replace = [...specials, ...customSpecials];
648
+ const replaceRegExp = convertToRegExp(replace);
649
+ replaceRegExp.forEach(([pattern, s]) => {
650
+ str = str.replace(pattern, s);
651
+ });
652
+ return str;
653
+ };
654
+
655
+ // src/model/defaults.ts
656
+ var slugToName = (slug) => {
657
+ const name = slug.replace(/([a-z])([A-Z])/g, "$1 $2");
658
+ return src_default(name);
659
+ };
660
+ var VOWELS = ["a", "e", "i", "o", "u"];
661
+ var pluralize = (word2) => {
662
+ const lastLetter = word2.slice(-1).toLowerCase();
663
+ const secondLastLetter = word2.slice(-2, -1).toLowerCase();
664
+ if (lastLetter === "y" && !VOWELS.includes(secondLastLetter)) {
665
+ return `${word2.slice(0, -1)}ies`;
516
666
  }
517
- Object.assign(toInstruction, defaultFields);
518
- for (const fieldSlug in toInstruction) {
519
- if (!Object.hasOwn(toInstruction, fieldSlug)) continue;
520
- const fieldValue = toInstruction[fieldSlug];
521
- const fieldDetails = getFieldFromModel(
522
- model,
523
- fieldSlug,
524
- { instructionName: "to" },
525
- false
526
- );
527
- if (fieldDetails?.field.type === "link" && fieldDetails.field.kind === "many") {
528
- delete toInstruction[fieldSlug];
529
- const associativeModelSlug = composeAssociationModelSlug(model, fieldDetails.field);
530
- const composeStatement = (subQueryType, value) => {
531
- const source = queryType === "add" ? toInstruction : withInstruction;
532
- const recordDetails = { source };
533
- if (value) recordDetails.target = value;
667
+ if (lastLetter === "s" || word2.slice(-2).toLowerCase() === "ch" || word2.slice(-2).toLowerCase() === "sh" || word2.slice(-2).toLowerCase() === "ex") {
668
+ return `${word2}es`;
669
+ }
670
+ return `${word2}s`;
671
+ };
672
+ var modelAttributes = [
673
+ ["pluralSlug", "slug", pluralize, true],
674
+ ["name", "slug", slugToName, false],
675
+ ["pluralName", "pluralSlug", slugToName, false],
676
+ ["idPrefix", "slug", (slug) => slug.slice(0, 3).toLowerCase(), false],
677
+ ["table", "pluralSlug", convertToSnakeCase, true]
678
+ ];
679
+ var getRecordIdentifier = (prefix) => {
680
+ return `${prefix}_${Array.from(crypto.getRandomValues(new Uint8Array(12))).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16).toLowerCase()}`;
681
+ };
682
+ var addDefaultModelAttributes = (model, isNew) => {
683
+ const copiedModel = { ...model };
684
+ if (isNew && !copiedModel.id) copiedModel.id = getRecordIdentifier("mod");
685
+ for (const [setting, base, generator, mustRegenerate] of modelAttributes) {
686
+ if (!(isNew || mustRegenerate)) continue;
687
+ if (copiedModel[setting] || !copiedModel[base]) continue;
688
+ copiedModel[setting] = generator(copiedModel[base]);
689
+ }
690
+ const newFields = copiedModel.fields || [];
691
+ if (isNew || Object.keys(newFields).length > 0) {
692
+ if (!copiedModel.identifiers) copiedModel.identifiers = {};
693
+ if (!copiedModel.identifiers.name) {
694
+ const suitableField = Object.entries(newFields).find(
695
+ ([fieldSlug, field]) => field.type === "string" && field.required === true && ["name"].includes(fieldSlug)
696
+ );
697
+ copiedModel.identifiers.name = suitableField?.[0] || "id";
698
+ }
699
+ if (!copiedModel.identifiers.slug) {
700
+ const suitableField = Object.entries(newFields).find(
701
+ ([fieldSlug, field]) => field.type === "string" && field.unique === true && field.required === true && ["slug", "handle"].includes(fieldSlug)
702
+ );
703
+ copiedModel.identifiers.slug = suitableField?.[0] || "id";
704
+ }
705
+ }
706
+ return copiedModel;
707
+ };
708
+ var addDefaultModelFields = (model, isNew) => {
709
+ const copiedModel = { ...model };
710
+ const existingFields = copiedModel.fields || [];
711
+ if (isNew || Object.keys(existingFields).length > 0) {
712
+ const additionalFields = Object.fromEntries(
713
+ Object.entries(getSystemFields(copiedModel.idPrefix)).filter(([newFieldSlug]) => {
714
+ return !Object.hasOwn(existingFields, newFieldSlug);
715
+ })
716
+ );
717
+ copiedModel.fields = { ...additionalFields, ...existingFields };
718
+ }
719
+ return copiedModel;
720
+ };
721
+ var addDefaultModelPresets = (list, model) => {
722
+ const defaultPresets = {};
723
+ for (const [fieldSlug, rest] of Object.entries(model.fields || {})) {
724
+ const field = { slug: fieldSlug, ...rest };
725
+ if (field.type === "link" && !fieldSlug.startsWith("ronin.")) {
726
+ const targetModel = getModelBySlug(list, field.target);
727
+ if (field.kind === "many") {
728
+ const systemModel = list.find(({ system }) => {
729
+ return system?.model === model.id && system?.associationSlug === field.slug;
730
+ });
731
+ if (!systemModel) continue;
732
+ const preset2 = {
733
+ instructions: {
734
+ // Perform a LEFT JOIN that adds the associative table.
735
+ including: {
736
+ [fieldSlug]: {
737
+ [QUERY_SYMBOLS.QUERY]: {
738
+ get: {
739
+ [systemModel.pluralSlug]: {
740
+ // ON associative_table.source = origin_model.id
741
+ with: {
742
+ source: {
743
+ [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}id`
744
+ }
745
+ },
746
+ // Perform a LEFT JOIN that adds the target model table.
747
+ including: {
748
+ [QUERY_SYMBOLS.QUERY]: {
749
+ get: {
750
+ [targetModel.slug]: {
751
+ // ON target_model.id = associative_table.target
752
+ with: {
753
+ id: {
754
+ [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}target`
755
+ }
756
+ }
757
+ }
758
+ }
759
+ }
760
+ },
761
+ selecting: ["**", "!source", "!target"]
762
+ }
763
+ }
764
+ }
765
+ }
766
+ }
767
+ }
768
+ };
769
+ defaultPresets[fieldSlug] = preset2;
770
+ continue;
771
+ }
772
+ const preset = {
773
+ instructions: {
774
+ including: {
775
+ [fieldSlug]: {
776
+ [QUERY_SYMBOLS.QUERY]: {
777
+ get: {
778
+ [targetModel.slug]: {
779
+ with: {
780
+ // Compare the `id` field of the related model to the link field on
781
+ // the root model (`field.slug`).
782
+ id: {
783
+ [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}${field.slug}`
784
+ }
785
+ }
786
+ }
787
+ }
788
+ }
789
+ }
790
+ }
791
+ }
792
+ };
793
+ defaultPresets[fieldSlug] = preset;
794
+ }
795
+ }
796
+ const childModels = list.map((subModel) => {
797
+ if (subModel.system?.associationSlug) return null;
798
+ const field = Object.entries(subModel.fields).find(([fieldSlug, rest]) => {
799
+ const field2 = { slug: fieldSlug, ...rest };
800
+ return field2.type === "link" && field2.target === model.slug;
801
+ });
802
+ if (!field) return null;
803
+ return { model: subModel, field: { slug: field[0], ...field[1] } };
804
+ }).filter((match) => match !== null);
805
+ for (const childMatch of childModels) {
806
+ const { model: childModel, field: childField } = childMatch;
807
+ const pluralSlug = childModel.pluralSlug;
808
+ const presetSlug = childModel.system?.associationSlug || pluralSlug;
809
+ const preset = {
810
+ instructions: {
811
+ including: {
812
+ [presetSlug]: {
813
+ [QUERY_SYMBOLS.QUERY]: {
814
+ get: {
815
+ [pluralSlug]: {
816
+ with: {
817
+ [childField.slug]: {
818
+ [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}id`
819
+ }
820
+ }
821
+ }
822
+ }
823
+ }
824
+ }
825
+ }
826
+ }
827
+ };
828
+ defaultPresets[presetSlug] = preset;
829
+ }
830
+ if (Object.keys(defaultPresets).length > 0) {
831
+ const existingPresets = model.presets;
832
+ const additionalPresets = Object.fromEntries(
833
+ Object.entries(defaultPresets).filter(([newPresetSlug]) => {
834
+ return !existingPresets?.[newPresetSlug];
835
+ })
836
+ );
837
+ model.presets = { ...additionalPresets, ...existingPresets };
838
+ }
839
+ return model;
840
+ };
841
+
842
+ // src/instructions/to.ts
843
+ var handleTo = (models, model, statementParams, queryType, dependencyStatements, instructions, options) => {
844
+ const { with: withInstruction, to: toInstruction } = instructions;
845
+ const defaultFields = {};
846
+ const currentTime = (/* @__PURE__ */ new Date()).toISOString();
847
+ if (queryType === "add" && options?.inlineDefaults) {
848
+ defaultFields.id = toInstruction.id || getRecordIdentifier(model.idPrefix);
849
+ }
850
+ if (queryType === "add" || queryType === "set" || toInstruction.ronin) {
851
+ const defaults = options?.inlineDefaults ? {
852
+ // If records are being created, set their creation time.
853
+ ...queryType === "add" && { createdAt: currentTime },
854
+ // If records are being updated or craeted, bump their update time.
855
+ updatedAt: currentTime,
856
+ // Allow for overwriting the default values provided above.
857
+ ...toInstruction.ronin
858
+ } : {
859
+ // If records are being updated, bump their update time.
860
+ ...queryType === "set" ? { updatedAt: CURRENT_TIME_EXPRESSION } : {},
861
+ // Allow for overwriting the default values provided above.
862
+ ...toInstruction.ronin
863
+ };
864
+ if (Object.keys(defaults).length > 0) defaultFields.ronin = defaults;
865
+ }
866
+ const symbol = getQuerySymbol(toInstruction);
867
+ if (symbol?.type === "query") {
868
+ const { queryModel: subQueryModelSlug, queryInstructions: subQueryInstructions } = splitQuery(symbol.value);
869
+ const subQueryModel = getModelBySlug(models, subQueryModelSlug);
870
+ const subQuerySelectedFields = subQueryInstructions?.selecting;
871
+ const subQueryIncludedFields = subQueryInstructions?.including;
872
+ const subQueryFields = [
873
+ ...filterSelectedFields(subQueryModel, subQuerySelectedFields).map(
874
+ (field) => field.slug
875
+ ),
876
+ ...subQueryIncludedFields ? Object.keys(
877
+ flatten(subQueryIncludedFields || {})
878
+ ) : []
879
+ ];
880
+ for (const field of subQueryFields || []) {
881
+ getFieldFromModel(model, field, { instructionName: "to" });
882
+ }
883
+ let statement2 = "";
884
+ if (subQuerySelectedFields) {
885
+ const columns = subQueryFields.map((field) => {
886
+ return getFieldFromModel(model, field, { instructionName: "to" }).fieldSelector;
887
+ });
888
+ statement2 = `(${columns.join(", ")}) `;
889
+ }
890
+ statement2 += compileQueryInput(symbol.value, models, statementParams, {
891
+ // biome-ignore lint/complexity/useSimplifiedLogicExpression: This is needed.
892
+ inlineDefaults: options?.inlineDefaults || false
893
+ }).main.statement;
894
+ return statement2;
895
+ }
896
+ Object.assign(toInstruction, defaultFields);
897
+ for (const fieldSlug in toInstruction) {
898
+ if (!Object.hasOwn(toInstruction, fieldSlug)) continue;
899
+ const fieldValue = toInstruction[fieldSlug];
900
+ const fieldDetails = getFieldFromModel(
901
+ model,
902
+ fieldSlug,
903
+ { instructionName: "to" },
904
+ false
905
+ );
906
+ if (fieldDetails?.field.type === "link" && fieldDetails.field.kind === "many") {
907
+ delete toInstruction[fieldSlug];
908
+ const associativeModelSlug = composeAssociationModelSlug(model, fieldDetails.field);
909
+ const composeStatement = (subQueryType, value) => {
910
+ const source = queryType === "add" ? toInstruction : withInstruction;
911
+ const recordDetails = { source };
912
+ if (value) recordDetails.target = value;
534
913
  const query = compileQueryInput(
535
914
  {
536
915
  [subQueryType]: {
@@ -1060,386 +1439,6 @@ var handleWith = (models, model, statementParams, instruction, parentModel) => {
1060
1439
  );
1061
1440
  };
1062
1441
 
1063
- // node_modules/title/dist/esm/lower-case.js
1064
- var conjunctions = [
1065
- "for",
1066
- "and",
1067
- "nor",
1068
- "but",
1069
- "or",
1070
- "yet",
1071
- "so"
1072
- ];
1073
- var articles = [
1074
- "a",
1075
- "an",
1076
- "the"
1077
- ];
1078
- var prepositions = [
1079
- "aboard",
1080
- "about",
1081
- "above",
1082
- "across",
1083
- "after",
1084
- "against",
1085
- "along",
1086
- "amid",
1087
- "among",
1088
- "anti",
1089
- "around",
1090
- "as",
1091
- "at",
1092
- "before",
1093
- "behind",
1094
- "below",
1095
- "beneath",
1096
- "beside",
1097
- "besides",
1098
- "between",
1099
- "beyond",
1100
- "but",
1101
- "by",
1102
- "concerning",
1103
- "considering",
1104
- "despite",
1105
- "down",
1106
- "during",
1107
- "except",
1108
- "excepting",
1109
- "excluding",
1110
- "following",
1111
- "for",
1112
- "from",
1113
- "in",
1114
- "inside",
1115
- "into",
1116
- "like",
1117
- "minus",
1118
- "near",
1119
- "of",
1120
- "off",
1121
- "on",
1122
- "onto",
1123
- "opposite",
1124
- "over",
1125
- "past",
1126
- "per",
1127
- "plus",
1128
- "regarding",
1129
- "round",
1130
- "save",
1131
- "since",
1132
- "than",
1133
- "through",
1134
- "to",
1135
- "toward",
1136
- "towards",
1137
- "under",
1138
- "underneath",
1139
- "unlike",
1140
- "until",
1141
- "up",
1142
- "upon",
1143
- "versus",
1144
- "via",
1145
- "with",
1146
- "within",
1147
- "without"
1148
- ];
1149
- var lowerCase = /* @__PURE__ */ new Set([
1150
- ...conjunctions,
1151
- ...articles,
1152
- ...prepositions
1153
- ]);
1154
-
1155
- // node_modules/title/dist/esm/specials.js
1156
- var specials = [
1157
- "ZEIT",
1158
- "ZEIT Inc.",
1159
- "Vercel",
1160
- "Vercel Inc.",
1161
- "CLI",
1162
- "API",
1163
- "HTTP",
1164
- "HTTPS",
1165
- "JSX",
1166
- "DNS",
1167
- "URL",
1168
- "now.sh",
1169
- "now.json",
1170
- "vercel.app",
1171
- "vercel.json",
1172
- "CI",
1173
- "CD",
1174
- "CDN",
1175
- "package.json",
1176
- "package.lock",
1177
- "yarn.lock",
1178
- "GitHub",
1179
- "GitLab",
1180
- "CSS",
1181
- "Sass",
1182
- "JS",
1183
- "JavaScript",
1184
- "TypeScript",
1185
- "HTML",
1186
- "WordPress",
1187
- "Next.js",
1188
- "Node.js",
1189
- "Webpack",
1190
- "Docker",
1191
- "Bash",
1192
- "Kubernetes",
1193
- "SWR",
1194
- "TinaCMS",
1195
- "UI",
1196
- "UX",
1197
- "TS",
1198
- "TSX",
1199
- "iPhone",
1200
- "iPad",
1201
- "watchOS",
1202
- "iOS",
1203
- "iPadOS",
1204
- "macOS",
1205
- "PHP",
1206
- "composer.json",
1207
- "composer.lock",
1208
- "CMS",
1209
- "SQL",
1210
- "C",
1211
- "C#",
1212
- "GraphQL",
1213
- "GraphiQL",
1214
- "JWT",
1215
- "JWTs"
1216
- ];
1217
-
1218
- // node_modules/title/dist/esm/index.js
1219
- var word = `[^\\s'\u2019\\(\\)!?;:"-]`;
1220
- var regex = new RegExp(`(?:(?:(\\s?(?:^|[.\\(\\)!?;:"-])\\s*)(${word}))|(${word}))(${word}*[\u2019']*${word}*)`, "g");
1221
- var convertToRegExp = (specials2) => specials2.map((s) => [new RegExp(`\\b${s}\\b`, "gi"), s]);
1222
- function parseMatch(match) {
1223
- const firstCharacter = match[0];
1224
- if (/\s/.test(firstCharacter)) {
1225
- return match.slice(1);
1226
- }
1227
- if (/[\(\)]/.test(firstCharacter)) {
1228
- return null;
1229
- }
1230
- return match;
1231
- }
1232
- var src_default = (str, options = {}) => {
1233
- str = str.toLowerCase().replace(regex, (m, lead = "", forced, lower, rest, offset, string) => {
1234
- const isLastWord = m.length + offset >= string.length;
1235
- const parsedMatch = parseMatch(m);
1236
- if (!parsedMatch) {
1237
- return m;
1238
- }
1239
- if (!forced) {
1240
- const fullLower = lower + rest;
1241
- if (lowerCase.has(fullLower) && !isLastWord) {
1242
- return parsedMatch;
1243
- }
1244
- }
1245
- return lead + (lower || forced).toUpperCase() + rest;
1246
- });
1247
- const customSpecials = options.special || [];
1248
- const replace = [...specials, ...customSpecials];
1249
- const replaceRegExp = convertToRegExp(replace);
1250
- replaceRegExp.forEach(([pattern, s]) => {
1251
- str = str.replace(pattern, s);
1252
- });
1253
- return str;
1254
- };
1255
-
1256
- // src/model/defaults.ts
1257
- var slugToName = (slug) => {
1258
- const name = slug.replace(/([a-z])([A-Z])/g, "$1 $2");
1259
- return src_default(name);
1260
- };
1261
- var VOWELS = ["a", "e", "i", "o", "u"];
1262
- var pluralize = (word2) => {
1263
- const lastLetter = word2.slice(-1).toLowerCase();
1264
- const secondLastLetter = word2.slice(-2, -1).toLowerCase();
1265
- if (lastLetter === "y" && !VOWELS.includes(secondLastLetter)) {
1266
- return `${word2.slice(0, -1)}ies`;
1267
- }
1268
- if (lastLetter === "s" || word2.slice(-2).toLowerCase() === "ch" || word2.slice(-2).toLowerCase() === "sh" || word2.slice(-2).toLowerCase() === "ex") {
1269
- return `${word2}es`;
1270
- }
1271
- return `${word2}s`;
1272
- };
1273
- var modelAttributes = [
1274
- ["pluralSlug", "slug", pluralize, true],
1275
- ["name", "slug", slugToName, false],
1276
- ["pluralName", "pluralSlug", slugToName, false],
1277
- ["idPrefix", "slug", (slug) => slug.slice(0, 3).toLowerCase(), false],
1278
- ["table", "pluralSlug", convertToSnakeCase, true]
1279
- ];
1280
- var getModelIdentifier = () => {
1281
- return `mod_${Array.from(crypto.getRandomValues(new Uint8Array(12))).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16).toLowerCase()}`;
1282
- };
1283
- var addDefaultModelAttributes = (model, isNew) => {
1284
- const copiedModel = { ...model };
1285
- if (isNew && !copiedModel.id) copiedModel.id = getModelIdentifier();
1286
- for (const [setting, base, generator, mustRegenerate] of modelAttributes) {
1287
- if (!(isNew || mustRegenerate)) continue;
1288
- if (copiedModel[setting] || !copiedModel[base]) continue;
1289
- copiedModel[setting] = generator(copiedModel[base]);
1290
- }
1291
- const newFields = copiedModel.fields || [];
1292
- if (isNew || Object.keys(newFields).length > 0) {
1293
- if (!copiedModel.identifiers) copiedModel.identifiers = {};
1294
- if (!copiedModel.identifiers.name) {
1295
- const suitableField = Object.entries(newFields).find(
1296
- ([fieldSlug, field]) => field.type === "string" && field.required === true && ["name"].includes(fieldSlug)
1297
- );
1298
- copiedModel.identifiers.name = suitableField?.[0] || "id";
1299
- }
1300
- if (!copiedModel.identifiers.slug) {
1301
- const suitableField = Object.entries(newFields).find(
1302
- ([fieldSlug, field]) => field.type === "string" && field.unique === true && field.required === true && ["slug", "handle"].includes(fieldSlug)
1303
- );
1304
- copiedModel.identifiers.slug = suitableField?.[0] || "id";
1305
- }
1306
- }
1307
- return copiedModel;
1308
- };
1309
- var addDefaultModelFields = (model, isNew) => {
1310
- const copiedModel = { ...model };
1311
- const existingFields = copiedModel.fields || [];
1312
- if (isNew || Object.keys(existingFields).length > 0) {
1313
- const additionalFields = Object.fromEntries(
1314
- Object.entries(getSystemFields(copiedModel.idPrefix)).filter(([newFieldSlug]) => {
1315
- return !Object.hasOwn(existingFields, newFieldSlug);
1316
- })
1317
- );
1318
- copiedModel.fields = { ...additionalFields, ...existingFields };
1319
- }
1320
- return copiedModel;
1321
- };
1322
- var addDefaultModelPresets = (list, model) => {
1323
- const defaultPresets = {};
1324
- for (const [fieldSlug, rest] of Object.entries(model.fields || {})) {
1325
- const field = { slug: fieldSlug, ...rest };
1326
- if (field.type === "link" && !fieldSlug.startsWith("ronin.")) {
1327
- const targetModel = getModelBySlug(list, field.target);
1328
- if (field.kind === "many") {
1329
- const systemModel = list.find(({ system }) => {
1330
- return system?.model === model.id && system?.associationSlug === field.slug;
1331
- });
1332
- if (!systemModel) continue;
1333
- const preset2 = {
1334
- instructions: {
1335
- // Perform a LEFT JOIN that adds the associative table.
1336
- including: {
1337
- [fieldSlug]: {
1338
- [QUERY_SYMBOLS.QUERY]: {
1339
- get: {
1340
- [systemModel.pluralSlug]: {
1341
- // ON associative_table.source = origin_model.id
1342
- with: {
1343
- source: {
1344
- [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}id`
1345
- }
1346
- },
1347
- // Perform a LEFT JOIN that adds the target model table.
1348
- including: {
1349
- [QUERY_SYMBOLS.QUERY]: {
1350
- get: {
1351
- [targetModel.slug]: {
1352
- // ON target_model.id = associative_table.target
1353
- with: {
1354
- id: {
1355
- [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}target`
1356
- }
1357
- }
1358
- }
1359
- }
1360
- }
1361
- },
1362
- selecting: ["**", "!source", "!target"]
1363
- }
1364
- }
1365
- }
1366
- }
1367
- }
1368
- }
1369
- };
1370
- defaultPresets[fieldSlug] = preset2;
1371
- continue;
1372
- }
1373
- const preset = {
1374
- instructions: {
1375
- including: {
1376
- [fieldSlug]: {
1377
- [QUERY_SYMBOLS.QUERY]: {
1378
- get: {
1379
- [targetModel.slug]: {
1380
- with: {
1381
- // Compare the `id` field of the related model to the link field on
1382
- // the root model (`field.slug`).
1383
- id: {
1384
- [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}${field.slug}`
1385
- }
1386
- }
1387
- }
1388
- }
1389
- }
1390
- }
1391
- }
1392
- }
1393
- };
1394
- defaultPresets[fieldSlug] = preset;
1395
- }
1396
- }
1397
- const childModels = list.map((subModel) => {
1398
- if (subModel.system?.associationSlug) return null;
1399
- const field = Object.entries(subModel.fields).find(([fieldSlug, rest]) => {
1400
- const field2 = { slug: fieldSlug, ...rest };
1401
- return field2.type === "link" && field2.target === model.slug;
1402
- });
1403
- if (!field) return null;
1404
- return { model: subModel, field: { slug: field[0], ...field[1] } };
1405
- }).filter((match) => match !== null);
1406
- for (const childMatch of childModels) {
1407
- const { model: childModel, field: childField } = childMatch;
1408
- const pluralSlug = childModel.pluralSlug;
1409
- const presetSlug = childModel.system?.associationSlug || pluralSlug;
1410
- const preset = {
1411
- instructions: {
1412
- including: {
1413
- [presetSlug]: {
1414
- [QUERY_SYMBOLS.QUERY]: {
1415
- get: {
1416
- [pluralSlug]: {
1417
- with: {
1418
- [childField.slug]: {
1419
- [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}id`
1420
- }
1421
- }
1422
- }
1423
- }
1424
- }
1425
- }
1426
- }
1427
- }
1428
- };
1429
- defaultPresets[presetSlug] = preset;
1430
- }
1431
- if (Object.keys(defaultPresets).length > 0) {
1432
- const existingPresets = model.presets;
1433
- const additionalPresets = Object.fromEntries(
1434
- Object.entries(defaultPresets).filter(([newPresetSlug]) => {
1435
- return !existingPresets?.[newPresetSlug];
1436
- })
1437
- );
1438
- model.presets = { ...additionalPresets, ...existingPresets };
1439
- }
1440
- return model;
1441
- };
1442
-
1443
1442
  // src/model/index.ts
1444
1443
  var getModelBySlug = (models, slug) => {
1445
1444
  const model = models.find((model2) => {
@@ -1500,7 +1499,12 @@ var getSystemFields = (idPrefix) => ({
1500
1499
  id: {
1501
1500
  name: "ID",
1502
1501
  type: "string",
1503
- defaultValue: ID_EXPRESSION(idPrefix)
1502
+ defaultValue: {
1503
+ // Since default values in SQLite cannot rely on other columns, we unfortunately
1504
+ // cannot rely on the `idPrefix` column here. Instead, we need to inject it
1505
+ // directly into the expression as a static string.
1506
+ [QUERY_SYMBOLS.EXPRESSION]: `'${idPrefix}_' || lower(substr(hex(randomblob(12)), 1, 16))`
1507
+ }
1504
1508
  },
1505
1509
  "ronin.createdAt": {
1506
1510
  name: "RONIN - Created At",
@@ -2004,10 +2008,11 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query,
2004
2008
  let json;
2005
2009
  switch (action) {
2006
2010
  case "create": {
2007
- const value = prepareStatementValue(statementParams, jsonValue);
2008
- json = `json_insert(${field}, '$.${slug}', ${value})`;
2011
+ const { slug: slug2, ...entityValue } = jsonValue;
2012
+ const value = prepareStatementValue(statementParams, entityValue);
2013
+ json = `json_insert(${field}, '$.${slug2}', ${value})`;
2009
2014
  if (!existingModel[pluralType]) existingModel[pluralType] = {};
2010
- existingModel[pluralType][slug] = jsonValue;
2015
+ existingModel[pluralType][slug2] = jsonValue;
2011
2016
  break;
2012
2017
  }
2013
2018
  case "alter": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronin/compiler",
3
- "version": "0.17.5",
3
+ "version": "0.17.6-leo-ron-1099-experimental-390",
4
4
  "type": "module",
5
5
  "description": "Compiles RONIN queries to SQL statements.",
6
6
  "publishConfig": {