/Post-processing mst-gql models Secret
Created
October 5, 2022 10:13
-
-
Save krstns/761a9f2a1f06627904e0db3289ab6cb0 to your computer and use it in GitHub Desktop.
Utility for post-processing MST models to workaround circular dependencies
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# expected arguments are the model source directory, and | |
# comma-separated list of root domains (same as in the generator config) | |
dir = ARGV[0] + '/*.ts' | |
configFile = ARGV[1] | |
File.read(configFile) =~ /roots: \[(.*)\]/ | |
rootModels = $1.gsub('"','').split(',').map(&:strip) | |
base_imports = { | |
# withTypedRefs: "import { withTypedRefs } from 'mst-gql'\n", | |
# MSTGQLRef: "import { MSTGQLRef } from 'mst-gql'\n", | |
ModelBase: "import { ModelBase } from './ModelBase'\n", | |
} | |
all_base_models = '' | |
root_store_base = '' | |
base_files = [] | |
root_store_base_file = '' | |
index_file = '' | |
rootModelTypeRegex = Regexp.union(rootModels.collect { |rm| ", #{rm}ModelType" }) | |
lateTypeModels = {} | |
indexts = '' | |
# iterate over all generated files | |
fileNum = 0 | |
Dir.glob(dir) do |fpath| | |
# process base model files first | |
if fpath =~ /\.base\.ts$/ | |
# save root store base file name for delayed processing | |
if fpath =~ /RootStore\.base/ | |
root_store_base_file = fpath | |
next | |
end | |
base_files.append(fpath) | |
File.open(fpath).each do |line| | |
if line =~ /^import/ | |
from = line.split(' ')[-1] | |
next if from.end_with?('.base"') | |
next if from.end_with?('Model"') | |
# next if from.end_with?('Enum"') | |
next if from.end_with?('ModelBase"') | |
if not base_imports[from] | |
# if line =~ /from "mst-gql"/ | |
# line.gsub!('from "mst-gql"', 'from "../lib"') | |
# end | |
base_imports[from] = line | |
end | |
next | |
end | |
next if line.start_with?('/* eslint') || | |
line.start_with?('/* tslint') || | |
line =~ /mst-gql generated file/ | |
if line =~ /types.late\(\(\): any \=\> ([^\)]+)/ | |
lower = "#{$1[0].downcase}#{$1[1..-1]}" | |
lateTypeModels[$1] = lower | |
code = "types.late((): any => #{$1})" | |
replace = "types.late((): any => #{lower}())" | |
line.sub!(code, replace) | |
end | |
if line =~ /self.__getStore/ | |
line.gsub!('<RootStoreType>', '') | |
end | |
if line =~ /^type Refs = {/ | |
line.gsub!('type Refs = {', "type Refs#{fileNum} = {") | |
end | |
if line =~ /withTypedRefs/ | |
line.gsub!('withTypedRefs<Refs>', "withTypedRefs<Refs#{fileNum}>") | |
end | |
all_base_models += line | |
end | |
all_base_models += "\n/******END CLASS******/" | |
fileNum = fileNum + 1 | |
next | |
end | |
# process regular model files | |
# update imports as needed | |
fname = fpath.split('/')[-1].split('.')[0] | |
file_stuff = '' | |
File.open(fpath).each do |line| | |
# if line =~ /from "mst-gql"/ | |
# file_stuff += line.gsub(/from "mst-gql"/, 'from "../lib"') | |
# next | |
# end | |
if fname == 'index' | |
goNext = false | |
puts line | |
rootModels.each do |rootModel| | |
if line =~ /export \* from \"\.\/#{rootModel}Model\"/ | |
puts "Removing export of #{rootModel}Model" | |
goNext = true | |
break | |
end | |
end | |
next if goNext | |
file_stuff += line | |
elsif fname != 'RootStore' | |
file_stuff += line.gsub(/\.\/.*\.base/, './AllBaseModels') | |
else | |
file_stuff += line | |
end | |
end | |
if fname == 'index' | |
file_stuff += "export * from './rootModelTypes'\n" | |
end | |
# write out new model file with new imports | |
puts 'Rewriting '+fpath | |
File.open(fpath, 'w') do |ff| | |
ff.write(file_stuff) | |
end | |
end | |
# rewrite RootStore.base with new imports | |
# and custom header | |
puts "Building RootStore.base.ts" | |
importModelTypes = '' | |
rootModels.each do |rootModel| | |
importModelTypes += "#{rootModel}ModelType, " | |
end | |
root_store_base += "import { #{importModelTypes}} from './rootModelTypes'\n" | |
File.open(root_store_base_file).each do |line| | |
if line =~ /^import/ | |
if line =~ /from "mst-gql"/ | |
# line.gsub!('from "mst-gql"', 'from "../lib"') | |
elsif line =~ /Model\.base/ | |
line.gsub!(/from "\.\/.*Model\.base"/, 'from "./AllBaseModels"') | |
end | |
else | |
next if line =~ /lint.disable/ | |
next if line =~ /mst-gql generated file/ | |
end | |
if line =~ /^import/ | |
line.gsub!(/#{rootModelTypeRegex}/, '') | |
end | |
root_store_base += line | |
end | |
base_hdr = "/* *** AUTOGENERATED FILES BY mst-gql *** DO NOT EDIT *** */\n" | |
base_hdr += "/* *** POST-PROCESSED WITH #{File.basename(__FILE__)} *** */\n" | |
base_hdr += "/* *** #{Time.now.utc.strftime('%FT%TZ')} *** */\n\n" | |
base_hdr += "/* eslint-disable */\n" | |
base_hdr += "/* tslint-disable */\n\n" | |
no_edit_hdr = base_hdr | |
rootModelTypeImports = 'import { ' | |
rootModels.each do |rootModel| | |
rootModelTypeImports += "#{rootModel}ModelType, " | |
end | |
rootModelTypeImports += '} from "./rootModelTypes"' | |
base_imports['rootModel'] = rootModelTypeImports | |
base_imports.each do |from, import| | |
next if import =~ /RootStoreType/ | |
base_hdr += import | |
end | |
base_hdr += "\nimport { \n" | |
lateTypeModels.each do |lateModel, lowercase| | |
base_hdr += " #{lowercase},\n" | |
end | |
base_hdr += "} from './lateModels'\n" | |
all_base_models = base_hdr + all_base_models | |
puts "Writing AllBaseModels.ts" | |
File.open(ARGV[0]+'/AllBaseModels.ts','w') do |ff| | |
ff.write(all_base_models) | |
end | |
# rootModelTypes.ts is used to remove circular dependencies | |
# between RootStore and the leaf model files | |
puts "Writing rootModelTypes.ts" | |
File.open(ARGV[0]+'/rootModelTypes.ts','w') do |ff| | |
ff.write(no_edit_hdr) | |
ff.write("import { Instance } from 'mobx-state-tree'\n") | |
exports = [] | |
rootModels.each do |rootModel| | |
ff.write("import { #{rootModel}Model } from './#{rootModel}Model'\n") | |
exp = "export type #{rootModel}ModelType = Instance<typeof #{rootModel}Model>\n" | |
exports.append(exp) | |
end | |
ff.write("\n") | |
exports.each do |exp| | |
ff.write(exp) | |
end | |
end | |
puts "Writing lateModels.ts" | |
File.open(ARGV[0]+'/lateModels.ts','w') do |ff| | |
ff.write(no_edit_hdr) | |
ff.write("/**** These functions embed requires for each model with a type.late reference to avoid circular depdencies from AllBaseModels ****/\n\n") | |
lateTypeModels.each do |lateModel, lowercase| | |
fcnName = lowercase | |
lateRequire = "let _#{fcnName}:any = undefined\n" | |
lateRequire += "export function #{fcnName}() {\n" | |
lateRequire += " if (!_#{fcnName}) {\n" | |
lateRequire += " _#{fcnName} = require('./#{lateModel}')\n" | |
lateRequire += " }\n" | |
lateRequire += " return (_#{fcnName} as any).#{lateModel}\n" | |
lateRequire += "}\n" | |
ff.write(lateRequire) | |
end | |
end | |
puts "Writing RootStore.base.ts file" | |
root_store_base = "#{no_edit_hdr}\n#{root_store_base}" | |
File.open(root_store_base_file,'w') do |ff| | |
ff.write(root_store_base) | |
end | |
puts 'Deleting base files...' | |
base_files.each do |fpath| | |
File.delete(fpath) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment