Smalltalk createPackage: 'Platform-ImportExport'! Object subclass: #AbstractExporter instanceVariableNames: '' package: 'Platform-ImportExport'! !AbstractExporter commentStamp! I am an abstract exporter for Amber source code. ## API Use `#exportPackage:on:` to export a given package on a Stream.! !AbstractExporter methodsFor: 'accessing'! extensionMethodsOfPackage: aPackage | result | result := OrderedCollection new. (self extensionProtocolsOfPackage: aPackage) do: [ :each | result addAll: each methods ]. ^ result ! extensionProtocolsOfPackage: aPackage | extensionName result | extensionName := '*', aPackage name. result := OrderedCollection new. "The classes must be loaded since it is extensions only. Therefore topological sorting (dependency resolution) does not matter here. Not sorting topologically improves the speed by a number of magnitude. Not to shuffle diffs, classes are sorted by their name." (Smalltalk classes asArray sorted: [ :a :b | a name < b name ]) do: [ :each | {each. each class} do: [ :behavior | (behavior protocols includes: extensionName) ifTrue: [ result add: (ExportMethodProtocol name: extensionName theClass: behavior) ] ] ]. ^ result ! ! !AbstractExporter methodsFor: 'convenience'! classNameFor: aClass ^ aClass isMetaclass ifTrue: [ aClass instanceClass name, ' class' ] ifFalse: [ aClass isNil ifTrue: [ 'nil' ] ifFalse: [ aClass name ] ] ! ! !AbstractExporter methodsFor: 'output'! exportPackage: aPackage on: aStream self subclassResponsibility ! ! AbstractExporter subclass: #ChunkExporter instanceVariableNames: '' package: 'Platform-ImportExport'! !ChunkExporter commentStamp! I am an exporter dedicated to outputting Amber source code in the classic Smalltalk chunk format. I do not output any compiled code.! !ChunkExporter methodsFor: 'accessing'! extensionCategoriesOfPackage: aPackage "Issue #143: sort protocol alphabetically" | name map result | name := aPackage name. result := OrderedCollection new. (Package sortedClasses: Smalltalk classes) do: [ :each | {each. each class} do: [ :aClass | map := Dictionary new. aClass protocolsDo: [ :category :methods | category = ('*', name) ifTrue: [ map at: category put: methods ] ]. result addAll: ((map keys sorted: [ :a :b | a <= b ]) collect: [ :category | MethodCategory name: category theClass: aClass methods: (map at: category) ]) ] ]. ^ result ! ownCategoriesOfClass: aClass "Answer the protocols of aClass that are not package extensions" "Issue #143: sort protocol alphabetically" | map | map := Dictionary new. aClass protocolsDo: [ :each :methods | (each match: '^\*') ifFalse: [ map at: each put: methods ] ]. ^ (map keys sorted: [ :a :b | a <= b ]) collect: [ :each | MethodCategory name: each theClass: aClass methods: (map at: each) ] ! ownCategoriesOfMetaClass: aClass "Issue #143: sort protocol alphabetically" ^ self ownCategoriesOfClass: aClass class ! ownMethodProtocolsOfClass: aClass "Answer a collection of ExportMethodProtocol object of aClass that are not package extensions" ^ aClass ownProtocols collect: [ :each | ExportMethodProtocol name: each theClass: aClass ] ! ! !ChunkExporter methodsFor: 'convenience'! chunkEscape: aString "Replace all occurrences of !! with !!!! and trim at both ends." ^ (aString replace: '!!' with: '!!!!') trimBoth ! ! !ChunkExporter methodsFor: 'output'! exportCategoryEpilogueOf: aCategory on: aStream aStream nextPutAll: ' !!'; lf; lf ! exportCategoryPrologueOf: aCategory on: aStream aStream nextPutAll: '!!', (self classNameFor: aCategory theClass); nextPutAll: ' methodsFor: ''', aCategory name, '''!!' ! exportDefinitionOf: aClass on: aStream "Chunk format." aStream nextPutAll: (self classNameFor: aClass superclass); nextPutAll: ' subclass: #', (self classNameFor: aClass); lf; tab; nextPutAll: 'instanceVariableNames: '''. aClass instanceVariableNames do: [ :each | aStream nextPutAll: each ] separatedBy: [ aStream nextPutAll: ' ' ]. aStream nextPutAll: ''''; lf; tab; nextPutAll: 'package: ''', aClass category, '''!!'; lf. aClass comment notEmpty ifTrue: [ aStream nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf; nextPutAll: (self chunkEscape: aClass comment), '!!';lf ]. aStream lf ! exportMetaDefinitionOf: aClass on: aStream aClass class instanceVariableNames isEmpty ifFalse: [ aStream nextPutAll: (self classNameFor: aClass class); nextPutAll: ' instanceVariableNames: '''. aClass class instanceVariableNames do: [ :each | aStream nextPutAll: each ] separatedBy: [ aStream nextPutAll: ' ' ]. aStream nextPutAll: '''!!'; lf; lf ] ! exportMethod: aMethod on: aStream aStream lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf; nextPutAll: '!!' ! exportPackage: aPackage on: aStream self exportPackageDefinitionOf: aPackage on: aStream; exportPackageImportsOf: aPackage on: aStream. aPackage sortedClasses do: [ :each | self exportDefinitionOf: each on: aStream. self exportProtocols: (self ownMethodProtocolsOfClass: each) on: aStream. self exportMetaDefinitionOf: each on: aStream. self exportProtocols: (self ownMethodProtocolsOfClass: each class) on: aStream ]. self exportProtocols: (self extensionProtocolsOfPackage: aPackage) on: aStream ! exportPackageDefinitionOf: aPackage on: aStream aStream nextPutAll: 'Smalltalk createPackage: ''', aPackage name, '''!!'; lf ! exportPackageImportsOf: aPackage on: aStream aPackage imports ifNotEmpty: [ :imports | aStream nextPutAll: '(Smalltalk packageAt: '''; nextPutAll: aPackage name; nextPutAll: ''') imports: '; nextPutAll: (self chunkEscape: aPackage importsDefinition); nextPutAll: '!!'; lf ] ! exportProtocol: aProtocol on: aStream self exportProtocolPrologueOf: aProtocol on: aStream. aProtocol methods do: [ :method | self exportMethod: method on: aStream ]. self exportProtocolEpilogueOf: aProtocol on: aStream ! exportProtocolEpilogueOf: aProtocol on: aStream aStream nextPutAll: ' !!'; lf; lf ! exportProtocolPrologueOf: aProtocol on: aStream aStream nextPutAll: '!!', (self classNameFor: aProtocol theClass); nextPutAll: ' methodsFor: ''', aProtocol name, '''!!' ! exportProtocols: aCollection on: aStream aCollection do: [ :each | self exportProtocol: each on: aStream ] ! ! AbstractExporter subclass: #Exporter instanceVariableNames: '' package: 'Platform-ImportExport'! !Exporter commentStamp! I am responsible for outputting Amber code into a JavaScript string. The generated output is enough to reconstruct the exported data, including Smalltalk source code and other metadata. ## Use case I am typically used to save code outside of the Amber runtime (committing to disk, etc.).! !Exporter methodsFor: 'accessing'! ownMethodsOfClass: aClass "Issue #143: sort methods alphabetically" ^ ((aClass methodDictionary values) sorted: [ :a :b | a selector <= b selector ]) reject: [ :each | (each protocol match: '^\*') ] ! ownMethodsOfMetaClass: aClass "Issue #143: sort methods alphabetically" ^ self ownMethodsOfClass: aClass class ! ! !Exporter methodsFor: 'convenience'! jsClassNameFor: aClass ^ aClass isMetaclass ifTrue: [ (self jsClassNameFor: aClass instanceClass), '.klass' ] ifFalse: [ aClass ifNil: [ 'null' ] ifNotNil: [ '$globals.', aClass name ] ] ! ! !Exporter methodsFor: 'output'! exportDefinitionOf: aClass on: aStream aStream lf; nextPutAll: '$core.addClass('; nextPutAll: '''', (self classNameFor: aClass), ''', '; nextPutAll: (self jsClassNameFor: aClass superclass); nextPutAll: ', ['. aClass instanceVariableNames do: [ :each | aStream nextPutAll: '''', each, '''' ] separatedBy: [ aStream nextPutAll: ', ' ]. aStream nextPutAll: '], '''; nextPutAll: aClass category, ''''; nextPutAll: ');'. aClass comment notEmpty ifTrue: [ aStream lf; nextPutAll: '//>>excludeStart("ide", pragmas.excludeIdeData);'; lf; nextPutAll: (self jsClassNameFor: aClass); nextPutAll: '.comment='; nextPutAll: aClass comment crlfSanitized asJavascript; nextPutAll: ';'; lf; nextPutAll: '//>>excludeEnd("ide");' ]. aStream lf ! exportMetaDefinitionOf: aClass on: aStream aStream lf. aClass class instanceVariableNames isEmpty ifFalse: [ aStream nextPutAll: (self jsClassNameFor: aClass class); nextPutAll: '.iVarNames = ['. aClass class instanceVariableNames do: [ :each | aStream nextPutAll: '''', each, '''' ] separatedBy: [ aStream nextPutAll: ',' ]. aStream nextPutAll: '];', String lf ] ! exportMethod: aMethod on: aStream aStream nextPutAll: '$core.addMethod(';lf; nextPutAll: '$core.method({';lf; nextPutAll: 'selector: ', aMethod selector asJavascript, ',';lf; nextPutAll: 'protocol: ''', aMethod protocol, ''',';lf; nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf; nextPutAll: '//>>excludeStart("ide", pragmas.excludeIdeData);';lf; nextPutAll: 'args: ', aMethod arguments asJavascript, ','; lf; nextPutAll: 'source: ', aMethod source asJavascript, ',';lf; nextPutAll: 'referencedClasses: ', aMethod referencedClasses asJavascript, ',';lf; nextPutAll: '//>>excludeEnd("ide");';lf; nextPutAll: 'messageSends: ', aMethod messageSends asJavascript;lf; nextPutAll: '}),';lf; nextPutAll: (self jsClassNameFor: aMethod methodClass); nextPutAll: ');';lf;lf ! exportPackage: aPackage on: aStream self exportPackagePrologueOf: aPackage on: aStream; exportPackageDefinitionOf: aPackage on: aStream; exportPackageContextOf: aPackage on: aStream; exportPackageImportsOf: aPackage on: aStream; exportPackageTransportOf: aPackage on: aStream. aPackage sortedClasses do: [ :each | self exportDefinitionOf: each on: aStream. each ownMethods do: [ :method | self exportMethod: method on: aStream ]. self exportMetaDefinitionOf: each on: aStream. each class ownMethods do: [ :method | self exportMethod: method on: aStream ] ]. (self extensionMethodsOfPackage: aPackage) do: [ :each | self exportMethod: each on: aStream ]. self exportPackageEpilogueOf: aPackage on: aStream ! exportPackageContextOf: aPackage on: aStream aStream nextPutAll: '$core.packages['; nextPutAll: aPackage name asJavascript; nextPutAll: '].innerEval = '; nextPutAll: 'function (expr) { return eval(expr); }'; nextPutAll: ';'; lf ! exportPackageDefinitionOf: aPackage on: aStream aStream nextPutAll: '$core.addPackage('; nextPutAll: '''', aPackage name, ''');'; lf ! exportPackageEpilogueOf: aPackage on: aStream self subclassResponsibility ! exportPackageImportsOf: aPackage on: aStream aPackage importsAsJson ifNotEmpty: [ :imports | aStream nextPutAll: '$core.packages['; nextPutAll: aPackage name asJavascript; nextPutAll: '].imports = '; nextPutAll: imports asJavascript; nextPutAll: ';'; lf ] ! exportPackagePrologueOf: aPackage on: aStream self subclassResponsibility ! exportPackageTransportOf: aPackage on: aStream aStream nextPutAll: '$core.packages['; nextPutAll: aPackage name asJavascript; nextPutAll: '].transport = '; nextPutAll: aPackage transport asJSONString; nextPutAll: ';'; lf ! ! Exporter subclass: #AmdExporter instanceVariableNames: 'namespace' package: 'Platform-ImportExport'! !AmdExporter commentStamp! I am used to export Packages in an AMD (Asynchronous Module Definition) JavaScript format.! !AmdExporter methodsFor: 'output'! exportPackageEpilogueOf: aPackage on: aStream aStream nextPutAll: '});'; lf ! exportPackagePrologueOf: aPackage on: aStream | importsForOutput loadDependencies pragmaStart pragmaEnd | pragmaStart := ''. pragmaEnd := ''. importsForOutput := self importsForOutput: aPackage. loadDependencies := self amdNamesOfPackages: aPackage loadDependencies. importsForOutput value ifNotEmpty: [ pragmaStart := String lf, '//>>excludeStart("imports", pragmas.excludeImports);', String lf. pragmaEnd := String lf, '//>>excludeEnd("imports");', String lf ]. aStream nextPutAll: 'define("'; nextPutAll: (self amdNamespaceOfPackage: aPackage); nextPutAll: '/'; nextPutAll: aPackage name; nextPutAll: '", '; nextPutAll: ((( (#('amber/boot' ':1:'), importsForOutput value, #(':2:'), loadDependencies) asJavascript) replace: ',\s*["'']:1:["'']' with: pragmaStart) replace: ',\s*["'']:2:["'']' with: pragmaEnd); nextPutAll: ', function('; nextPutAll: ((( (#('$boot' ':1:'), importsForOutput key, #(':2:')) join: ',') replace: ',\s*:1:' with: pragmaStart) replace: ',\s*:2:' with: pragmaEnd); nextPutAll: '){"use strict";'; lf; nextPutAll: 'var $core=$boot.api,nil=$boot.nil,$recv=$boot.asReceiver,$globals=$boot.globals;'; lf ! ! !AmdExporter methodsFor: 'private'! amdNamesOfPackages: anArray ^ (anArray select: [ :each | (self amdNamespaceOfPackage: each) notNil ]) collect: [ :each | (self amdNamespaceOfPackage: each), '/', each name ] ! amdNamespaceOfPackage: aPackage ^ (aPackage transport type = 'amd') ifTrue: [ aPackage transport namespace ] ifFalse: [ nil ] ! importsForOutput: aPackage "Returns an association where key is list of import variables and value is list of external dependencies, with ones imported as variables put at the beginning with same order as is in key. For example imports:{'jQuery'->'jquery'. 'bootstrap'} would yield #('jQuery') -> #('jquery' 'bootstrap')" | namedImports anonImports importVarNames | namedImports := #(). anonImports := #(). importVarNames := #(). aPackage imports do: [ :each | each isString ifTrue: [ anonImports add: each ] ifFalse: [ namedImports add: each value. importVarNames add: each key ]]. ^ importVarNames -> (namedImports, anonImports) ! ! Object subclass: #ChunkParser instanceVariableNames: 'stream last' package: 'Platform-ImportExport'! !ChunkParser commentStamp! I am responsible for parsing aStream contents in the chunk format. ## API ChunkParser new stream: aStream; nextChunk! !ChunkParser methodsFor: 'accessing'! last ^ last ! stream: aStream stream := aStream ! ! !ChunkParser methodsFor: 'reading'! nextChunk "The chunk format (Smalltalk Interchange Format or Fileout format) is a trivial format but can be a bit tricky to understand: - Uses the exclamation mark as delimiter of chunks. - Inside a chunk a normal exclamation mark must be doubled. - A non empty chunk must be a valid Smalltalk expression. - A chunk on top level with a preceding empty chunk is an instruction chunk: - The object created by the expression then takes over reading chunks. This method returns next chunk as a String (trimmed), empty String (all whitespace) or nil." | char result chunk | result := '' writeStream. [ char := stream next. char notNil ] whileTrue: [ char = '!!' ifTrue: [ stream peek = '!!' ifTrue: [ stream next "skipping the escape double" ] ifFalse: [ ^ last := result contents trimBoth "chunk end marker found" ]]. result nextPut: char ]. ^ last := nil "a chunk needs to end with !!" ! ! !ChunkParser class methodsFor: 'instance creation'! on: aStream ^ self new stream: aStream ! ! Object subclass: #ClassCommentReader instanceVariableNames: 'class' package: 'Platform-ImportExport'! !ClassCommentReader commentStamp! I provide a mechanism for retrieving class comments stored on a file. See also `ClassCategoryReader`.! !ClassCommentReader methodsFor: 'accessing'! class: aClass class := aClass ! ! !ClassCommentReader methodsFor: 'fileIn'! scanFrom: aChunkParser | chunk | chunk := aChunkParser nextChunk. chunk isEmpty ifFalse: [ self setComment: chunk ]. ! ! !ClassCommentReader methodsFor: 'initialization'! initialize super initialize. ! ! !ClassCommentReader methodsFor: 'private'! setComment: aString class comment: aString ! ! Object subclass: #ClassProtocolReader instanceVariableNames: 'class category' package: 'Platform-ImportExport'! !ClassProtocolReader commentStamp! I provide a mechanism for retrieving class descriptions stored on a file in the Smalltalk chunk format.! !ClassProtocolReader methodsFor: 'accessing'! class: aClass category: aString class := aClass. category := aString ! ! !ClassProtocolReader methodsFor: 'fileIn'! scanFrom: aChunkParser | chunk | [ chunk := aChunkParser nextChunk. chunk isEmpty ] whileFalse: [ self compileMethod: chunk ]. ClassBuilder new setupClass: class ! ! !ClassProtocolReader methodsFor: 'initialization'! initialize super initialize. ! ! !ClassProtocolReader methodsFor: 'private'! compileMethod: aString Compiler new install: aString forClass: class protocol: category ! ! Object subclass: #ExportMethodProtocol instanceVariableNames: 'name theClass' package: 'Platform-ImportExport'! !ExportMethodProtocol commentStamp! I am an abstraction for a method protocol in a class / metaclass. I know of my class, name and methods. I am used when exporting a package.! !ExportMethodProtocol methodsFor: 'accessing'! methods ^ (self theClass methodsInProtocol: self name) sorted: [ :a :b | a selector <= b selector ] ! name ^ name ! name: aString name := aString ! theClass ^ theClass ! theClass: aClass theClass := aClass ! ! !ExportMethodProtocol class methodsFor: 'instance creation'! name: aString theClass: aClass ^ self new name: aString; theClass: aClass; yourself ! ! Object subclass: #Importer instanceVariableNames: 'lastSection lastChunk' package: 'Platform-ImportExport'! !Importer commentStamp! I can import Amber code from a string in the chunk format. ## API Importer new import: aString! !Importer methodsFor: 'accessing'! lastChunk ^ lastChunk ! lastSection ^ lastSection ! ! !Importer methodsFor: 'fileIn'! import: aStream | chunk result parser lastEmpty | parser := ChunkParser on: aStream. lastEmpty := false. lastSection := 'n/a, not started'. lastChunk := nil. [ [ chunk := parser nextChunk. chunk isNil ] whileFalse: [ chunk isEmpty ifTrue: [ lastEmpty := true ] ifFalse: [ lastSection := chunk. result := Compiler new evaluateExpression: chunk. lastEmpty ifTrue: [ lastEmpty := false. result scanFrom: parser ]] ]. lastSection := 'n/a, finished' ] on: Error do: [:e | lastChunk := parser last. e resignal ]. ! ! Error subclass: #PackageCommitError instanceVariableNames: '' package: 'Platform-ImportExport'! !PackageCommitError commentStamp! I get signaled when an attempt to commit a package has failed.! InterfacingObject subclass: #PackageHandler instanceVariableNames: '' package: 'Platform-ImportExport'! !PackageHandler commentStamp! I am responsible for handling package loading and committing. I should not be used directly. Instead, use the corresponding `Package` methods.! !PackageHandler methodsFor: 'accessing'! chunkContentsFor: aPackage ^ String streamContents: [ :str | self chunkExporter exportPackage: aPackage on: str ] ! chunkExporterClass ^ ChunkExporter ! commitPathJsFor: aPackage self subclassResponsibility ! commitPathStFor: aPackage self subclassResponsibility ! contentsFor: aPackage ^ String streamContents: [ :str | self exporter exportPackage: aPackage on: str ] ! exporterClass self subclassResponsibility ! ! !PackageHandler methodsFor: 'committing'! commit: aPackage self commit: aPackage onSuccess: [] onError: [ :error | PackageCommitError new messageText: 'Commiting failed with reason: "' , (error responseText) , '"'; signal ] ! commit: aPackage onSuccess: aBlock onError: anotherBlock self commitJsFileFor: aPackage onSuccess: [ self commitStFileFor: aPackage onSuccess: [ aPackage beClean. aBlock value ] onError: anotherBlock ] onError: anotherBlock ! commitJsFileFor: aPackage onSuccess: aBlock onError: anotherBlock self ajaxPutAt: (self commitPathJsFor: aPackage), '/', aPackage name, '.js' data: (self contentsFor: aPackage) onSuccess: aBlock onError: anotherBlock ! commitStFileFor: aPackage onSuccess: aBlock onError: anotherBlock self ajaxPutAt: (self commitPathStFor: aPackage), '/', aPackage name, '.st' data: (self chunkContentsFor: aPackage) onSuccess: aBlock onError: anotherBlock ! ! !PackageHandler methodsFor: 'error handling'! onCommitError: anError PackageCommitError new messageText: 'Commiting failed with reason: "' , (anError responseText) , '"'; signal ! ! !PackageHandler methodsFor: 'factory'! chunkExporter ^ self chunkExporterClass new ! exporter ^ self exporterClass new ! ! !PackageHandler methodsFor: 'loading'! load: aPackage self subclassResponsibility ! ! !PackageHandler methodsFor: 'private'! ajaxPutAt: aURL data: aString onSuccess: aBlock onError: anotherBlock | xhr | xhr := Platform newXhr. xhr open: 'PUT' url: aURL async: true. xhr onreadystatechange: [ xhr readyState = 4 ifTrue: [ (xhr status >= 200 and: [ xhr status < 300 ]) ifTrue: aBlock ifFalse: anotherBlock ]]. xhr send: aString ! ! PackageHandler subclass: #AmdPackageHandler instanceVariableNames: '' package: 'Platform-ImportExport'! !AmdPackageHandler commentStamp! I am responsible for handling package loading and committing. I should not be used directly. Instead, use the corresponding `Package` methods.! !AmdPackageHandler methodsFor: 'accessing'! commitPathJsFor: aPackage ^ self toUrl: (self namespaceFor: aPackage) ! commitPathStFor: aPackage "If _source is not mapped, .st will be committed to .js path. It is recommended not to use _source as it can be deprecated." | path pathWithout | path := self toUrl: (self namespaceFor: aPackage), '/_source'. pathWithout := self commitPathJsFor: aPackage. ^ path = (pathWithout, '/_source') ifTrue: [ pathWithout ] ifFalse: [ path ] ! exporterClass ^ AmdExporter ! ! !AmdPackageHandler methodsFor: 'committing'! namespaceFor: aPackage ^ aPackage transport namespace ! ! !AmdPackageHandler methodsFor: 'loading'! load: aPackage Smalltalk amdRequire ifNil: [ self error: 'AMD loader not present' ] ifNotNil: [ :require | require value: (Array with: (self namespaceFor: aPackage), '/', aPackage name ) ] ! ! !AmdPackageHandler methodsFor: 'private'! toUrl: aString ^ Smalltalk amdRequire ifNil: [ self error: 'AMD loader not present' ] ifNotNil: [ :require | (require basicAt: 'toUrl') value: aString ] ! ! !AmdPackageHandler class methodsFor: 'commit paths'! defaultNamespace ^ Smalltalk defaultAmdNamespace ! defaultNamespace: aString Smalltalk defaultAmdNamespace: aString ! ! Object subclass: #PackageTransport instanceVariableNames: 'package' package: 'Platform-ImportExport'! !PackageTransport commentStamp! I represent the transport mechanism used to commit a package. My concrete subclasses have a `#handler` to which committing is delegated.! !PackageTransport methodsFor: 'accessing'! commitHandlerClass self subclassResponsibility ! definition ^ '' ! package ^ package ! package: aPackage package := aPackage ! type ^ self class type ! ! !PackageTransport methodsFor: 'committing'! commit self commitHandler commit: self package ! commitOnSuccess: aBlock onError: anotherBlock self commitHandler commit: self package onSuccess: aBlock onError: anotherBlock ! ! !PackageTransport methodsFor: 'converting'! asJSON ^ #{ 'type' -> self type } ! ! !PackageTransport methodsFor: 'factory'! commitHandler ^ self commitHandlerClass new ! ! !PackageTransport methodsFor: 'initialization'! setupFromJson: anObject "no op. override if needed in subclasses" ! ! !PackageTransport methodsFor: 'loading'! load self commitHandler load: self package ! ! PackageTransport class instanceVariableNames: 'registry'! !PackageTransport class methodsFor: 'accessing'! classRegisteredFor: aString ^ registry at: aString ! defaultType ^ AmdPackageTransport type ! type "Override in subclasses" ^ nil ! ! !PackageTransport class methodsFor: 'initialization'! initialize super initialize. self == PackageTransport ifTrue: [ registry := #{} ] ifFalse: [ self register ] ! ! !PackageTransport class methodsFor: 'instance creation'! for: aString ^ (self classRegisteredFor: aString) new ! fromJson: anObject anObject ifNil: [ ^ self for: self defaultType ]. ^ (self for: anObject type) setupFromJson: anObject; yourself ! ! !PackageTransport class methodsFor: 'registration'! register PackageTransport register: self ! register: aClass aClass type ifNotNil: [ registry at: aClass type put: aClass ] ! ! PackageTransport subclass: #AmdPackageTransport instanceVariableNames: 'namespace' package: 'Platform-ImportExport'! !AmdPackageTransport commentStamp! I am the default transport for committing packages. See `AmdExporter` and `AmdPackageHandler`.! !AmdPackageTransport methodsFor: 'accessing'! commitHandlerClass ^ AmdPackageHandler ! definition ^ String streamContents: [ :stream | stream nextPutAll: self class name; nextPutAll: ' namespace: '; nextPutAll: '''', self namespace, '''' ] ! namespace ^ namespace ifNil: [ self defaultNamespace ] ! namespace: aString namespace := aString ! ! !AmdPackageTransport methodsFor: 'actions'! setPath: aString "Set the path the the receiver's `namespace`" (require basicAt: 'config') value: #{ 'paths' -> #{ self namespace -> aString } }. ! ! !AmdPackageTransport methodsFor: 'converting'! asJSON ^ super asJSON at: 'amdNamespace' put: self namespace; yourself ! ! !AmdPackageTransport methodsFor: 'defaults'! defaultNamespace ^ Smalltalk defaultAmdNamespace ! ! !AmdPackageTransport methodsFor: 'initialization'! setupFromJson: anObject self namespace: (anObject at: 'amdNamespace') ! ! !AmdPackageTransport methodsFor: 'printing'! printOn: aStream super printOn: aStream. aStream nextPutAll: ' (AMD Namespace: '; nextPutAll: self namespace; nextPutAll: ')' ! ! !AmdPackageTransport class methodsFor: 'accessing'! type ^ 'amd' ! ! !AmdPackageTransport class methodsFor: 'instance creation'! namespace: aString ^ self new namespace: aString; yourself ! ! !Behavior methodsFor: '*Platform-ImportExport'! commentStamp ^ ClassCommentReader new class: self; yourself ! commentStamp: aStamp prior: prior ^ self commentStamp ! methodsFor: aString ^ ClassProtocolReader new class: self category: aString; yourself ! methodsFor: aString stamp: aStamp "Added for file-in compatibility, ignores stamp." ^ self methodsFor: aString ! ! !Package methodsFor: '*Platform-ImportExport'! commit ^ self transport commit ! load ^ self transport load ! loadFromNamespace: aString ^ self transport namespace: aString; load ! ! !Package class methodsFor: '*Platform-ImportExport'! load: aPackageName (self named: aPackageName) load ! load: aPackageName fromNamespace: aString (self named: aPackageName) loadFromNamespace: aString ! !