@atomic-ehr/codegen 0.0.1-canary.20251010131311.9439f74 → 0.0.1-canary.20251013100511.ff2ef29

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.
package/dist/index.d.ts CHANGED
@@ -757,6 +757,7 @@ interface APIBuilderOptions {
757
757
  typeSchemaConfig?: TypeSchemaConfig;
758
758
  logger?: CodegenLogger;
759
759
  manager?: ReturnType<typeof CanonicalManager> | null;
760
+ typeSchemaOutputDir?: string /** if .ndjson -- put in one file, else -- split into separated files*/;
760
761
  throwException?: boolean;
761
762
  }
762
763
  /**
@@ -826,6 +827,8 @@ declare class APIBuilder {
826
827
  verbose(enabled?: boolean): APIBuilder;
827
828
  throwException(enabled?: boolean): APIBuilder;
828
829
  cleanOutput(enabled?: boolean): APIBuilder;
830
+ writeTypeSchemas(target: string): this;
831
+ private tryWriteTypeSchema;
829
832
  generate(): Promise<GenerationResult>;
830
833
  /**
831
834
  * Generate and return the results without writing to files
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { CanonicalManager } from '@atomic-ehr/fhir-canonical-manager';
2
2
  import * as fhirschema from '@atomic-ehr/fhirschema';
3
3
  import * as fs from 'fs';
4
4
  import { existsSync, mkdirSync } from 'fs';
5
+ import * as afs from 'fs/promises';
5
6
  import { readdir, stat, unlink, readFile, writeFile, access, mkdir, rm } from 'fs/promises';
6
7
  import * as Path2 from 'path';
7
8
  import { join, resolve, dirname, relative } from 'path';
@@ -2945,6 +2946,33 @@ var generateTypeSchemas = async (register, logger) => {
2945
2946
  return fhirSchemas;
2946
2947
  };
2947
2948
 
2949
+ // src/api/writer-generator/utils.ts
2950
+ var words = (s) => {
2951
+ return s.split(/(?<=[a-z])(?=[A-Z])|[-_.\s]/).filter(Boolean);
2952
+ };
2953
+ var kebabCase = (s) => {
2954
+ return words(s).map((s2) => s2.toLowerCase()).join("-");
2955
+ };
2956
+ var capitalCase = (s) => {
2957
+ if (s.length === 0) throw new Error("Empty string");
2958
+ return s[0]?.toUpperCase() + s.substring(1).toLowerCase();
2959
+ };
2960
+ var camelCase = (s) => {
2961
+ if (s.length === 0) throw new Error("Empty string");
2962
+ const [first, ...rest] = words(s);
2963
+ return [first?.toLowerCase(), ...rest.map(capitalCase)].join("");
2964
+ };
2965
+ var pascalCase = (s) => {
2966
+ return words(s).map(capitalCase).join("");
2967
+ };
2968
+ var uppercaseFirstLetter = (str) => {
2969
+ if (!str || str.length === 0) return str;
2970
+ return str.charAt(0).toUpperCase() + str.slice(1);
2971
+ };
2972
+ var uppercaseFirstLetterOfEach = (strings) => {
2973
+ return strings.map((str) => uppercaseFirstLetter(str));
2974
+ };
2975
+
2948
2976
  // src/typeschema/utils.ts
2949
2977
  var groupByPackages = (typeSchemas) => {
2950
2978
  const grouped = {};
@@ -4162,8 +4190,8 @@ function toCamelCase(str) {
4162
4190
  return str.replace(/[-_\s]+(.)?/g, (_, char) => char?.toUpperCase() || "");
4163
4191
  }
4164
4192
  function toPascalCase(str) {
4165
- const camelCase = toCamelCase(str);
4166
- return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
4193
+ const camelCase2 = toCamelCase(str);
4194
+ return camelCase2.charAt(0).toUpperCase() + camelCase2.slice(1);
4167
4195
  }
4168
4196
  function toSnakeCase(str) {
4169
4197
  return str.replace(/([A-Z])/g, "_$1").replace(/[-\s]+/g, "_").toLowerCase().replace(/^_/, "");
@@ -4890,7 +4918,7 @@ ${nestedInterfaces}`;
4890
4918
  }
4891
4919
  const optional = required ? "" : "?";
4892
4920
  const arrayType = isArray ? "[]" : "";
4893
- return `${fieldName.replace("-", "_")}${optional}: ${typeString}${arrayType};`;
4921
+ return `${fieldName}${optional}: ${typeString}${arrayType};`;
4894
4922
  }
4895
4923
  // ==========================================
4896
4924
  /**
@@ -5112,28 +5140,6 @@ ${nestedInterfaces}`;
5112
5140
  );
5113
5141
  }
5114
5142
  };
5115
-
5116
- // src/api/writer-generator/utils.ts
5117
- var words = (s) => {
5118
- return s.split(/(?<=[a-z])(?=[A-Z])|[-_.\s]/).filter(Boolean);
5119
- };
5120
- var kebabCase = (s) => {
5121
- return words(s).map((s2) => s2.toLowerCase()).join("-");
5122
- };
5123
- var capitalCase = (s) => {
5124
- if (s.length === 0) throw new Error("Empty string");
5125
- return s[0]?.toUpperCase() + s.substring(1).toLowerCase();
5126
- };
5127
- var pascalCase = (s) => {
5128
- return words(s).map(capitalCase).join("");
5129
- };
5130
- var uppercaseFirstLetter = (str) => {
5131
- if (!str || str.length === 0) return str;
5132
- return str.charAt(0).toUpperCase() + str.slice(1);
5133
- };
5134
- var uppercaseFirstLetterOfEach = (strings) => {
5135
- return strings.map((str) => uppercaseFirstLetter(str));
5136
- };
5137
5143
  var FileSystemWriter = class {
5138
5144
  opts;
5139
5145
  currentDir;
@@ -5319,12 +5325,20 @@ var tsResourceName = (id) => {
5319
5325
  }
5320
5326
  return normalizeTsName(id.name);
5321
5327
  };
5322
- var tsFieldName = (n) => normalizeTsName(n);
5328
+ var tsKeywords = /* @__PURE__ */ new Set(["class", "function", "return", "if", "for", "while", "const", "let", "var", "import", "export", "interface"]);
5329
+ var tsFieldName = (n) => {
5330
+ if (tsKeywords.has(n)) return `"${n}"`;
5331
+ if (n.includes(" ") || n.includes("-")) return `"${n}"`;
5332
+ return n;
5333
+ };
5323
5334
  var normalizeTsName = (n) => {
5324
- const tsKeywords = /* @__PURE__ */ new Set(["abstract", "any", "as", "async", "await", "boolean", "bigint", "break", "case", "catch", "class", "const", "constructor", "continue", "debugger", "declare", "default", "delete", "do", "else", "enum", "export", "extends", "extern", "false", "finally", "for", "function", "from", "get", "goto", "if", "implements", "import", "in", "infer", "instanceof", "interface", "keyof", "let", "module", "namespace", "never", "new", "null", "number", "object", "of", "override", "private", "protected", "public", "readonly", "return", "satisfies", "set", "static", "string", "super", "switch", "this", "throw", "true", "try", "type", "typeof", "unknown", "var", "void", "while"]);
5325
5335
  if (tsKeywords.has(n)) n = `${n}_`;
5326
5336
  return n.replace(/[- ]/g, "_");
5327
5337
  };
5338
+ var tsGet = (object, tsFieldName2) => {
5339
+ if (tsFieldName2.startsWith('"')) return `${object}[${tsFieldName2}]`;
5340
+ return `${object}.${tsFieldName2}`;
5341
+ };
5328
5342
  var TypeScript = class extends Writer {
5329
5343
  tsImportType(tsPackageName, ...entities) {
5330
5344
  this.lineSM(`import type { ${entities.join(", ")} } from "${tsPackageName}"`);
@@ -5388,7 +5402,8 @@ var TypeScript = class extends Writer {
5388
5402
  }
5389
5403
  addFieldExtension(fieldName, field) {
5390
5404
  if (field.type.kind === "primitive-type") {
5391
- this.lineSM(`_${tsFieldName(fieldName)}?: Element`);
5405
+ const extFieldName = tsFieldName(`_${fieldName}`);
5406
+ this.lineSM(`${extFieldName}?: Element`);
5392
5407
  }
5393
5408
  }
5394
5409
  generateType(tsIndex, schema) {
@@ -5513,7 +5528,7 @@ var TypeScript = class extends Writer {
5513
5528
  this.line(`profile: ['${flatProfile.identifier.url}']`);
5514
5529
  }, [","]);
5515
5530
  profileFields.forEach((fieldName) => {
5516
- this.line(`${fieldName}:`, `profile.${fieldName},`);
5531
+ this.line(`${fieldName}: ${tsGet("profile", fieldName)},`);
5517
5532
  });
5518
5533
  });
5519
5534
  }
@@ -5544,7 +5559,7 @@ var TypeScript = class extends Writer {
5544
5559
  if (!isNotChoiceDeclarationField(pField) || !isNotChoiceDeclarationField(rField)) return;
5545
5560
  if (pField.required && !rField.required) {
5546
5561
  this.curlyBlock(
5547
- [`if (resource.${tsField} === undefined)`],
5562
+ [`if (${tsGet("resource", tsField)} === undefined)`],
5548
5563
  () => this.lineSM(
5549
5564
  `throw new Error("'${tsField}' is required for ${flatProfile.identifier.url}")`
5550
5565
  )
@@ -5563,11 +5578,11 @@ var TypeScript = class extends Writer {
5563
5578
  this.line(";");
5564
5579
  });
5565
5580
  });
5566
- let cond = !pField?.required ? `!resource.${tsField} || ` : "";
5581
+ let cond = !pField?.required ? `!${tsGet("resource", tsField)} || ` : "";
5567
5582
  if (pField.array) {
5568
- cond += `resource.${tsField}.every( (ref) => ${predName}(ref) )`;
5583
+ cond += `${tsGet("resource", tsField)}.every( (ref) => ${predName}(ref) )`;
5569
5584
  } else {
5570
- cond += `!${predName}(resource.${tsField})`;
5585
+ cond += `!${predName}(${tsGet("resource", tsField)})`;
5571
5586
  }
5572
5587
  this.curlyBlock(["if (", cond, ")"], () => {
5573
5588
  this.lineSM(
@@ -5583,9 +5598,12 @@ var TypeScript = class extends Writer {
5583
5598
  profileFields.forEach((fieldName) => {
5584
5599
  const tsField = tsFieldName(fieldName);
5585
5600
  if (shouldCast[fieldName]) {
5586
- this.line(`${tsField}:`, `resource.${tsField} as ${tsProfileName}['${tsField}'],`);
5601
+ this.line(
5602
+ `${tsField}:`,
5603
+ `${tsGet("resource", tsField)} as ${tsProfileName}['${tsField}'],`
5604
+ );
5587
5605
  } else {
5588
- this.line(`${tsField}:`, `resource.${tsField},`);
5606
+ this.line(`${tsField}:`, `${tsGet("resource", tsField)},`);
5589
5607
  }
5590
5608
  });
5591
5609
  });
@@ -5657,6 +5675,7 @@ var writerToGenerator = (writerGen) => {
5657
5675
  build: async (_schemas) => getGeneratedFiles()
5658
5676
  };
5659
5677
  };
5678
+ var normalizeFileName = (str) => str.replace(/[^a-zA-Z0-9]/g, "");
5660
5679
  var APIBuilder = class {
5661
5680
  schemas = [];
5662
5681
  options;
@@ -5677,7 +5696,8 @@ var APIBuilder = class {
5677
5696
  cleanOutput: options.cleanOutput ?? true,
5678
5697
  typeSchemaConfig: options.typeSchemaConfig,
5679
5698
  manager: options.manager || null,
5680
- throwException: options.throwException || false
5699
+ throwException: options.throwException || false,
5700
+ typeSchemaOutputDir: options.typeSchemaOutputDir
5681
5701
  };
5682
5702
  this.typeSchemaConfig = options.typeSchemaConfig;
5683
5703
  this.logger = options.logger || createLogger({
@@ -5780,6 +5800,45 @@ var APIBuilder = class {
5780
5800
  this.options.cleanOutput = enabled;
5781
5801
  return this;
5782
5802
  }
5803
+ writeTypeSchemas(target) {
5804
+ this.options.typeSchemaOutputDir = target;
5805
+ return this;
5806
+ }
5807
+ async tryWriteTypeSchema(typeSchemas) {
5808
+ if (!this.options.typeSchemaOutputDir) return;
5809
+ try {
5810
+ if (this.options.cleanOutput) fs.rmSync(this.options.typeSchemaOutputDir, { recursive: true, force: true });
5811
+ await afs.mkdir(this.options.typeSchemaOutputDir, { recursive: true });
5812
+ let writtenCount = 0;
5813
+ let overrideCount = 0;
5814
+ const usedNames = {};
5815
+ this.logger.info(`Writing TypeSchema files to ${this.options.typeSchemaOutputDir}...`);
5816
+ for (const ts of typeSchemas) {
5817
+ const package_name = camelCase(ts.identifier.package.replaceAll("/", "-"));
5818
+ const name = normalizeFileName(ts.identifier.name.toString());
5819
+ const baseName = Path2.join(this.options.typeSchemaOutputDir, package_name, name);
5820
+ let fullName;
5821
+ if (usedNames[baseName] !== void 0) {
5822
+ usedNames[baseName]++;
5823
+ fullName = `${baseName}-${usedNames[baseName]}.typeschema.json`;
5824
+ } else {
5825
+ usedNames[baseName] = 0;
5826
+ fullName = `${baseName}.typeschema.json`;
5827
+ }
5828
+ await afs.mkdir(Path2.dirname(fullName), { recursive: true });
5829
+ afs.writeFile(fullName, JSON.stringify(ts, null, 2));
5830
+ if (await afs.exists(fullName)) overrideCount++;
5831
+ else writtenCount++;
5832
+ }
5833
+ this.logger.info(`Created ${writtenCount} new TypeSchema files, overrode ${overrideCount} files`);
5834
+ } catch (error) {
5835
+ if (this.options.throwException) throw error;
5836
+ this.logger.error(
5837
+ "Failed to write TypeSchema output",
5838
+ error instanceof Error ? error : new Error(String(error))
5839
+ );
5840
+ }
5841
+ }
5783
5842
  async generate() {
5784
5843
  const startTime = performance.now();
5785
5844
  const result = {
@@ -5811,6 +5870,7 @@ var APIBuilder = class {
5811
5870
  await manager.init();
5812
5871
  const register = await registerFromManager(manager, this.logger);
5813
5872
  const typeSchemas = await generateTypeSchemas(register, this.logger);
5873
+ await this.tryWriteTypeSchema(typeSchemas);
5814
5874
  this.logger.debug(`Executing ${this.generators.size} generators`);
5815
5875
  await this.executeGenerators(result, typeSchemas);
5816
5876
  this.logger.info("Generation completed successfully");