Importer-Exporter.st 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. Smalltalk current createPackage: 'Importer-Exporter'!
  2. Object subclass: #ChunkExporter
  3. instanceVariableNames: ''
  4. package: 'Importer-Exporter'!
  5. !ChunkExporter commentStamp!
  6. I am an exporter dedicated to outputting Amber source code in the classic Smalltalk chunk format.
  7. I do not output any compiled code.!
  8. !ChunkExporter class methodsFor: 'exporting-accessing'!
  9. extensionCategoriesOfPackage: package
  10. "Issue #143: sort protocol alphabetically"
  11. | name map result |
  12. name := package name.
  13. result := OrderedCollection new.
  14. (Package sortedClasses: Smalltalk current classes) do: [:each |
  15. {each. each class} do: [:aClass |
  16. map := Dictionary new.
  17. aClass protocolsDo: [:category :methods |
  18. (category match: '^\*', name) ifTrue: [ map at: category put: methods ]].
  19. result addAll: ((map keys sorted: [:a :b | a <= b ]) collect: [:category |
  20. MethodCategory name: category theClass: aClass methods: (map at: category)]) ]].
  21. ^result
  22. !
  23. methodsOfCategory: category
  24. "Issue #143: sort methods alphabetically"
  25. ^(category methods) sorted: [:a :b | a selector <= b selector]
  26. !
  27. ownCategoriesOfClass: aClass
  28. "Issue #143: sort protocol alphabetically"
  29. | map |
  30. map := Dictionary new.
  31. aClass protocolsDo: [:category :methods |
  32. (category match: '^\*') ifFalse: [ map at: category put: methods ]].
  33. ^(map keys sorted: [:a :b | a <= b ]) collect: [:category |
  34. MethodCategory name: category theClass: aClass methods: (map at: category) ]
  35. !
  36. ownCategoriesOfMetaClass: aClass
  37. "Issue #143: sort protocol alphabetically"
  38. ^self ownCategoriesOfClass: aClass class
  39. ! !
  40. !ChunkExporter class methodsFor: 'exporting-output'!
  41. exportCategoryEpilogueOf: category on: aStream
  42. aStream nextPutAll: ' !!'; lf; lf
  43. !
  44. exportCategoryPrologueOf: category on: aStream
  45. aStream
  46. nextPutAll: '!!', (self classNameFor: category theClass);
  47. nextPutAll: ' methodsFor: ''', category name, '''!!'
  48. !
  49. exportDefinitionOf: aClass on: aStream
  50. "Chunk format."
  51. aStream
  52. nextPutAll: (self classNameFor: aClass superclass);
  53. nextPutAll: ' subclass: #', (self classNameFor: aClass); lf;
  54. tab; nextPutAll: 'instanceVariableNames: '''.
  55. aClass instanceVariableNames
  56. do: [:each | aStream nextPutAll: each]
  57. separatedBy: [aStream nextPutAll: ' '].
  58. aStream
  59. nextPutAll: ''''; lf;
  60. tab; nextPutAll: 'package: ''', aClass category, '''!!'; lf.
  61. aClass comment notEmpty ifTrue: [
  62. aStream
  63. nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;
  64. nextPutAll: (self chunkEscape: aClass comment), '!!';lf].
  65. aStream lf
  66. !
  67. exportMetaDefinitionOf: aClass on: aStream
  68. aClass class instanceVariableNames isEmpty ifFalse: [
  69. aStream
  70. nextPutAll: (self classNameFor: aClass class);
  71. nextPutAll: ' instanceVariableNames: '''.
  72. aClass class instanceVariableNames
  73. do: [:each | aStream nextPutAll: each]
  74. separatedBy: [aStream nextPutAll: ' '].
  75. aStream
  76. nextPutAll: '''!!'; lf; lf]
  77. !
  78. exportMethod: aMethod on: aStream
  79. aStream
  80. lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf;
  81. nextPutAll: '!!'
  82. !
  83. exportPackageDefinitionOf: package on: aStream
  84. "Chunk format."
  85. aStream
  86. nextPutAll: 'Smalltalk current createPackage: ''', package name, '''!!';
  87. lf
  88. ! !
  89. !ChunkExporter class methodsFor: 'fileOut'!
  90. recipe
  91. "Export a given package."
  92. | exportCategoryRecipe |
  93. exportCategoryRecipe := {
  94. self -> #exportCategoryPrologueOf:on:.
  95. {
  96. self -> #methodsOfCategory:.
  97. self -> #exportMethod:on: }.
  98. self -> #exportCategoryEpilogueOf:on: }.
  99. ^{
  100. self -> #exportPackageDefinitionOf:on:.
  101. {
  102. PluggableExporter -> #ownClassesOfPackage:.
  103. self -> #exportDefinitionOf:on:.
  104. { self -> #ownCategoriesOfClass: }, exportCategoryRecipe.
  105. self -> #exportMetaDefinitionOf:on:.
  106. { self -> #ownCategoriesOfMetaClass: }, exportCategoryRecipe }.
  107. { self -> #extensionCategoriesOfPackage: }, exportCategoryRecipe
  108. }
  109. ! !
  110. !ChunkExporter class methodsFor: 'private'!
  111. chunkEscape: aString
  112. "Replace all occurrences of !! with !!!! and trim at both ends."
  113. ^(aString replace: '!!' with: '!!!!') trimBoth
  114. !
  115. classNameFor: aClass
  116. ^aClass isMetaclass
  117. ifTrue: [aClass instanceClass name, ' class']
  118. ifFalse: [
  119. aClass isNil
  120. ifTrue: ['nil']
  121. ifFalse: [aClass name]]
  122. ! !
  123. Object subclass: #ChunkParser
  124. instanceVariableNames: 'stream'
  125. package: 'Importer-Exporter'!
  126. !ChunkParser commentStamp!
  127. I am responsible for parsing aStream contents in the chunk format.
  128. ## API
  129. ChunkParser new
  130. stream: aStream;
  131. nextChunk!
  132. !ChunkParser methodsFor: 'accessing'!
  133. stream: aStream
  134. stream := aStream
  135. ! !
  136. !ChunkParser methodsFor: 'reading'!
  137. nextChunk
  138. "The chunk format (Smalltalk Interchange Format or Fileout format)
  139. is a trivial format but can be a bit tricky to understand:
  140. - Uses the exclamation mark as delimiter of chunks.
  141. - Inside a chunk a normal exclamation mark must be doubled.
  142. - A non empty chunk must be a valid Smalltalk expression.
  143. - A chunk on top level with a preceding empty chunk is an instruction chunk:
  144. - The object created by the expression then takes over reading chunks.
  145. This metod returns next chunk as a String (trimmed), empty String (all whitespace) or nil."
  146. | char result chunk |
  147. result := '' writeStream.
  148. [char := stream next.
  149. char notNil] whileTrue: [
  150. char = '!!' ifTrue: [
  151. stream peek = '!!'
  152. ifTrue: [stream next "skipping the escape double"]
  153. ifFalse: [^result contents trimBoth "chunk end marker found"]].
  154. result nextPut: char].
  155. ^nil "a chunk needs to end with !!"
  156. ! !
  157. !ChunkParser class methodsFor: 'not yet classified'!
  158. on: aStream
  159. ^self new stream: aStream
  160. ! !
  161. Object subclass: #Exporter
  162. instanceVariableNames: ''
  163. package: 'Importer-Exporter'!
  164. !Exporter commentStamp!
  165. I am responsible for outputting Amber code into a JavaScript string.
  166. The generated output is enough to reconstruct the exported data, including Smalltalk source code and other metadata.
  167. ## Use case
  168. I am typically used to save code outside of the Amber runtime (committing to disk, etc.).
  169. ## API
  170. Use `#exportAll`, `#exportClass:` or `#exportPackage:` methods.!
  171. !Exporter class methodsFor: 'exporting-accessing'!
  172. extensionMethodsOfPackage: package
  173. "Issue #143: sort classes and methods alphabetically"
  174. | name result |
  175. name := package name.
  176. result := OrderedCollection new.
  177. (Package sortedClasses: Smalltalk current classes) do: [:each |
  178. {each. each class} do: [:aClass |
  179. result addAll: (((aClass methodDictionary values)
  180. sorted: [:a :b | a selector <= b selector])
  181. select: [:method | method category match: '^\*', name]) ]].
  182. ^result
  183. !
  184. ownMethodsOfClass: aClass
  185. "Issue #143: sort methods alphabetically"
  186. ^((aClass methodDictionary values) sorted: [:a :b | a selector <= b selector])
  187. reject: [:each | (each category match: '^\*')]
  188. !
  189. ownMethodsOfMetaClass: aClass
  190. "Issue #143: sort methods alphabetically"
  191. ^self ownMethodsOfClass: aClass class
  192. ! !
  193. !Exporter class methodsFor: 'exporting-output'!
  194. exportDefinitionOf: aClass on: aStream
  195. aStream
  196. lf;
  197. nextPutAll: 'smalltalk.addClass(';
  198. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  199. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  200. nextPutAll: ', ['.
  201. aClass instanceVariableNames
  202. do: [:each | aStream nextPutAll: '''', each, '''']
  203. separatedBy: [aStream nextPutAll: ', '].
  204. aStream
  205. nextPutAll: '], ''';
  206. nextPutAll: aClass category, '''';
  207. nextPutAll: ');'.
  208. aClass comment notEmpty ifTrue: [
  209. aStream
  210. lf;
  211. nextPutAll: 'smalltalk.';
  212. nextPutAll: (self classNameFor: aClass);
  213. nextPutAll: '.comment=';
  214. nextPutAll: aClass comment asJavascript;
  215. nextPutAll: ';'].
  216. aStream lf
  217. !
  218. exportMetaDefinitionOf: aClass on: aStream
  219. aStream lf.
  220. aClass class instanceVariableNames isEmpty ifFalse: [
  221. aStream
  222. nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
  223. nextPutAll: '.iVarNames = ['.
  224. aClass class instanceVariableNames
  225. do: [:each | aStream nextPutAll: '''', each, '''']
  226. separatedBy: [aStream nextPutAll: ','].
  227. aStream nextPutAll: '];', String lf]
  228. !
  229. exportMethod: aMethod on: aStream
  230. aStream
  231. nextPutAll: 'smalltalk.addMethod(';lf;
  232. "nextPutAll: aMethod selector asSelector asJavascript, ',';lf;"
  233. nextPutAll: 'smalltalk.method({';lf;
  234. nextPutAll: 'selector: ', aMethod selector asJavascript, ',';lf;
  235. nextPutAll: 'category: ''', aMethod category, ''',';lf;
  236. nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
  237. nextPutAll: 'args: ', aMethod arguments asJavascript, ','; lf;
  238. nextPutAll: 'source: ', aMethod source asJavascript, ',';lf;
  239. nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;
  240. nextPutAll: 'referencedClasses: ', aMethod referencedClasses asJavascript.
  241. aStream
  242. lf;
  243. nextPutAll: '}),';lf;
  244. nextPutAll: 'smalltalk.', (self classNameFor: aMethod methodClass);
  245. nextPutAll: ');';lf;lf
  246. !
  247. exportPackageDefinitionOf: package on: aStream
  248. aStream
  249. nextPutAll: 'smalltalk.addPackage(';
  250. nextPutAll: '''', package name, ''');';
  251. lf
  252. !
  253. exportPackageEpilogueOf: aPackage on: aStream
  254. aStream
  255. nextPutAll: '})(global_smalltalk,global_nil,global__st);';
  256. lf
  257. !
  258. exportPackagePrologueOf: aPackage on: aStream
  259. aStream
  260. nextPutAll: '(function(smalltalk,nil,_st){';
  261. lf
  262. ! !
  263. !Exporter class methodsFor: 'fileOut'!
  264. recipe
  265. "Export a given package."
  266. ^{
  267. self -> #exportPackagePrologueOf:on:.
  268. self -> #exportPackageDefinitionOf:on:.
  269. {
  270. PluggableExporter -> #ownClassesOfPackage:.
  271. self -> #exportDefinitionOf:on:.
  272. {
  273. self -> #ownMethodsOfClass:.
  274. self -> #exportMethod:on: }.
  275. self -> #exportMetaDefinitionOf:on:.
  276. {
  277. self -> #ownMethodsOfMetaClass:.
  278. self -> #exportMethod:on: } }.
  279. {
  280. self -> #extensionMethodsOfPackage:.
  281. self -> #exportMethod:on: }.
  282. self -> #exportPackageEpilogueOf:on:
  283. }
  284. ! !
  285. !Exporter class methodsFor: 'private'!
  286. classNameFor: aClass
  287. ^aClass isMetaclass
  288. ifTrue: [aClass instanceClass name, '.klass']
  289. ifFalse: [
  290. aClass isNil
  291. ifTrue: ['nil']
  292. ifFalse: [aClass name]]
  293. ! !
  294. Exporter subclass: #StrippedExporter
  295. instanceVariableNames: ''
  296. package: 'Importer-Exporter'!
  297. !StrippedExporter commentStamp!
  298. I export Amber code into a JavaScript string, but without any optional associated data like the Amber source code.!
  299. !StrippedExporter class methodsFor: 'exporting-output'!
  300. exportDefinitionOf: aClass on: aStream
  301. aStream
  302. lf;
  303. nextPutAll: 'smalltalk.addClass(';
  304. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  305. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  306. nextPutAll: ', ['.
  307. aClass instanceVariableNames
  308. do: [:each | aStream nextPutAll: '''', each, '''']
  309. separatedBy: [aStream nextPutAll: ', '].
  310. aStream
  311. nextPutAll: '], ''';
  312. nextPutAll: aClass category, '''';
  313. nextPutAll: ');'.
  314. aStream lf
  315. !
  316. exportMethod: aMethod on: aStream
  317. aStream
  318. nextPutAll: 'smalltalk.addMethod(';lf;
  319. "nextPutAll: aMethod selector asSelector asJavascript, ',';lf;"
  320. nextPutAll: 'smalltalk.method({';lf;
  321. nextPutAll: 'selector: ', aMethod selector asJavascript, ',';lf;
  322. nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
  323. nextPutAll: 'messageSends: ', aMethod messageSends asJavascript;
  324. nextPutAll: '}),';lf;
  325. nextPutAll: 'smalltalk.', (self classNameFor: aMethod methodClass);
  326. nextPutAll: ');';lf;lf
  327. ! !
  328. Object subclass: #Importer
  329. instanceVariableNames: ''
  330. package: 'Importer-Exporter'!
  331. !Importer commentStamp!
  332. I can import Amber code from a string in the chunk format.
  333. ## API
  334. Importer new import: aString!
  335. !Importer methodsFor: 'fileIn'!
  336. import: aStream
  337. | chunk result parser lastEmpty |
  338. parser := ChunkParser on: aStream.
  339. lastEmpty := false.
  340. [chunk := parser nextChunk.
  341. chunk isNil] whileFalse: [
  342. chunk isEmpty
  343. ifTrue: [lastEmpty := true]
  344. ifFalse: [
  345. result := Compiler new evaluateExpression: chunk.
  346. lastEmpty
  347. ifTrue: [
  348. lastEmpty := false.
  349. result scanFrom: parser]]]
  350. ! !
  351. Object subclass: #MethodCategory
  352. instanceVariableNames: 'methods name theClass'
  353. package: 'Importer-Exporter'!
  354. !MethodCategory methodsFor: 'accessing'!
  355. methods
  356. ^methods
  357. !
  358. methods: anArray
  359. methods := anArray
  360. !
  361. name
  362. ^name
  363. !
  364. name: aString
  365. name := aString
  366. !
  367. theClass
  368. ^theClass
  369. !
  370. theClass: aClass
  371. theClass := aClass
  372. ! !
  373. !MethodCategory class methodsFor: 'not yet classified'!
  374. name: aString theClass: aClass methods: anArray
  375. ^self new
  376. name: aString;
  377. theClass: aClass;
  378. methods: anArray;
  379. yourself
  380. ! !
  381. InterfacingObject subclass: #PackageHandler
  382. instanceVariableNames: ''
  383. package: 'Importer-Exporter'!
  384. !PackageHandler commentStamp!
  385. I am responsible for handling package loading and committing.
  386. I should not be used directly. Instead, use the corresponding `Package` methods.!
  387. !PackageHandler methodsFor: 'committing'!
  388. commit: aPackage
  389. self commitChannels
  390. do: [ :commitStrategyFactory || fileContents commitStrategy |
  391. commitStrategy := commitStrategyFactory value: aPackage.
  392. fileContents := String streamContents: [ :stream |
  393. (PluggableExporter newUsing: commitStrategy key) exportPackage: aPackage on: stream ].
  394. self ajaxPutAt: commitStrategy value data: fileContents ]
  395. displayingProgress: 'Committing package ', aPackage name
  396. !
  397. commitChannels
  398. self subclassResponsibility
  399. ! !
  400. !PackageHandler methodsFor: 'private'!
  401. ajaxPutAt: aURL data: aString
  402. self
  403. ajax: #{
  404. 'url' -> aURL.
  405. 'type' -> 'PUT'.
  406. 'data' -> aString.
  407. 'contentType' -> 'text/plain;charset=UTF-8'.
  408. 'error' -> [ :xhr | self error: 'Commiting ' , aURL , ' failed with reason: "' , (xhr responseText) , '"'] }
  409. ! !
  410. PackageHandler class instanceVariableNames: 'registry'!
  411. !PackageHandler class methodsFor: 'accessing'!
  412. classRegisteredFor: aString
  413. ^registry at: aString
  414. !
  415. for: aString
  416. ^(self classRegisteredFor: aString) new
  417. ! !
  418. !PackageHandler class methodsFor: 'initialization'!
  419. initialize
  420. super initialize.
  421. registry := #{}
  422. ! !
  423. !PackageHandler class methodsFor: 'registry'!
  424. register: aClass for: aString
  425. registry at: aString put: aClass
  426. !
  427. registerFor: aString
  428. PackageHandler register: self for: aString
  429. ! !
  430. PackageHandler subclass: #LegacyPackageHandler
  431. instanceVariableNames: ''
  432. package: 'Importer-Exporter'!
  433. !LegacyPackageHandler commentStamp!
  434. I am responsible for handling package loading and committing.
  435. I should not be used directly. Instead, use the corresponding `Package` methods.!
  436. !LegacyPackageHandler methodsFor: 'committing'!
  437. commitChannels
  438. ^{
  439. [ :pkg | Exporter recipe -> (pkg commitPathJs, '/', pkg name, '.js') ].
  440. [ :pkg | StrippedExporter recipe -> (pkg commitPathJs, '/', pkg name, '.deploy.js') ].
  441. [ :pkg | ChunkExporter recipe -> (pkg commitPathSt, '/', pkg name, '.st') ]
  442. }
  443. !
  444. commitPathJsFor: aPackage
  445. ^self class defaultCommitPathJs
  446. !
  447. commitPathStFor: aPackage
  448. ^self class defaultCommitPathSt
  449. ! !
  450. !LegacyPackageHandler methodsFor: 'loading'!
  451. loadPackage: packageName prefix: aString
  452. | url |
  453. url := '/', aString, '/js/', packageName, '.js'.
  454. self
  455. ajax: #{
  456. 'url' -> url.
  457. 'type' -> 'GET'.
  458. 'dataType' -> 'script'.
  459. 'complete' -> [ :jqXHR :textStatus |
  460. jqXHR readyState = 4
  461. ifTrue: [ self setupPackageNamed: packageName prefix: aString ] ].
  462. 'error' -> [ self alert: 'Could not load package at: ', url ]
  463. }
  464. !
  465. loadPackages: aCollection prefix: aString
  466. aCollection do: [ :each |
  467. self loadPackage: each prefix: aString ]
  468. ! !
  469. !LegacyPackageHandler methodsFor: 'private'!
  470. setupPackageNamed: packageName prefix: aString
  471. (Package named: packageName)
  472. setupClasses;
  473. commitPathJs: '/', aString, '/js';
  474. commitPathSt: '/', aString, '/st'
  475. ! !
  476. LegacyPackageHandler class instanceVariableNames: 'defaultCommitPathJs defaultCommitPathSt'!
  477. !LegacyPackageHandler class methodsFor: 'commit paths'!
  478. commitPathsFromLoader
  479. <
  480. var commitPath = typeof amber !!== 'undefined' && amber.commitPath;
  481. if (!!commitPath) return;
  482. if (commitPath.js) self._defaultCommitPathJs_(commitPath.js);
  483. if (commitPath.st) self._defaultCommitPathSt_(commitPath.st);
  484. >
  485. !
  486. defaultCommitPathJs
  487. ^ defaultCommitPathJs ifNil: [ defaultCommitPathJs := 'js']
  488. !
  489. defaultCommitPathJs: aString
  490. defaultCommitPathJs := aString
  491. !
  492. defaultCommitPathSt
  493. ^ defaultCommitPathSt ifNil: [ defaultCommitPathSt := 'st']
  494. !
  495. defaultCommitPathSt: aString
  496. defaultCommitPathSt := aString
  497. !
  498. resetCommitPaths
  499. defaultCommitPathJs := nil.
  500. defaultCommitPathSt := nil
  501. ! !
  502. !LegacyPackageHandler class methodsFor: 'initialization'!
  503. initialize
  504. super initialize.
  505. self registerFor: 'unknown'.
  506. self commitPathsFromLoader
  507. ! !
  508. !LegacyPackageHandler class methodsFor: 'loading'!
  509. loadPackages: aCollection prefix: aString
  510. ^ self new loadPackages: aCollection prefix: aString
  511. ! !
  512. Object subclass: #PluggableExporter
  513. instanceVariableNames: 'recipe'
  514. package: 'Importer-Exporter'!
  515. !PluggableExporter methodsFor: 'accessing'!
  516. recipe
  517. ^recipe
  518. !
  519. recipe: anArray
  520. recipe := anArray
  521. ! !
  522. !PluggableExporter methodsFor: 'fileOut'!
  523. export: anObject usingRecipe: anArray on: aStream
  524. | args |
  525. args := { anObject. aStream }.
  526. anArray do: [ :each | | val |
  527. val := each value.
  528. val == each
  529. ifFalse: [ "association"
  530. each key perform: val withArguments: args ]
  531. ifTrue: [ "sub-array"
  532. | selection |
  533. selection := each first key perform: each first value withArguments: { anObject }.
  534. selection do: [ :eachPart | self export: eachPart usingRecipe: each allButFirst on: aStream ]]]
  535. !
  536. exportAll
  537. "Export all packages in the system."
  538. ^String streamContents: [:stream |
  539. Smalltalk current packages do: [:pkg |
  540. self exportPackage: pkg on: stream]]
  541. !
  542. exportPackage: aPackage on: aStream
  543. self export: aPackage usingRecipe: self recipe on: aStream
  544. ! !
  545. !PluggableExporter class methodsFor: 'exporting-accessing'!
  546. newUsing: recipe
  547. ^self new recipe: recipe; yourself
  548. !
  549. ownClassesOfPackage: package
  550. "Export classes in dependency order.
  551. Update (issue #171): Remove duplicates for export"
  552. ^package sortedClasses asSet
  553. ! !
  554. !Package methodsFor: '*Importer-Exporter'!
  555. commit
  556. ^ self transport commit: self
  557. !
  558. commitPathJs
  559. ^ (extension ifNil: [ extension := #{} ]) at: #commitPathJs ifAbsentPut: [self transport commitPathJsFor: self]
  560. !
  561. commitPathJs: aString
  562. ^ (extension ifNil: [ extension := #{} ]) at: #commitPathJs put: aString
  563. !
  564. commitPathSt
  565. ^ (extension ifNil: [ extension := #{} ]) at: #commitPathSt ifAbsentPut: [self transport commitPathStFor: self]
  566. !
  567. commitPathSt: aString
  568. ^ (extension ifNil: [ extension := #{} ]) at: #commitPathSt put: aString
  569. !
  570. transport
  571. ^ PackageHandler for: self transportType
  572. !
  573. transportType
  574. <return (self.transport && self.transport.type) || 'unknown';>
  575. ! !