@@ -47,6 +47,8 @@ class Resource {
4747 #lastModified;
4848 #statInfo;
4949 #isDirectory;
50+ #integrity;
51+ #inode;
5052
5153 /* States */
5254 #isModified = false ;
@@ -91,10 +93,12 @@ class Resource {
9193 * @param {boolean } [parameters.isDirectory] Flag whether the resource represents a directory
9294 * @param {number } [parameters.byteSize] Size of the resource content in bytes
9395 * @param {number } [parameters.lastModified] Last modified timestamp (in milliseconds since UNIX epoch)
96+ * @param {string } [parameters.integrity] Integrity hash of the resource content
97+ * @param {number } [parameters.inode] Inode number of the resource
9498 */
9599 constructor ( {
96100 path, statInfo, buffer, createBuffer, string, createStream, stream, project, sourceMetadata,
97- isDirectory, byteSize, lastModified,
101+ isDirectory, byteSize, lastModified, integrity , inode ,
98102 } ) {
99103 if ( ! path ) {
100104 throw new Error ( "Unable to create Resource: Missing parameter 'path'" ) ;
@@ -194,13 +198,21 @@ class Resource {
194198 this . #lastModified = lastModified ;
195199 }
196200
201+ if ( inode !== undefined ) {
202+ if ( typeof inode !== "number" || inode < 0 ) {
203+ throw new Error ( "Unable to create Resource: Parameter 'inode' must be a positive number" ) ;
204+ }
205+ this . #inode = inode ;
206+ }
207+
197208 if ( statInfo ) {
198209 this . #isDirectory ??= statInfo . isDirectory ( ) ;
199210 if ( ! this . #isDirectory && statInfo . isFile && ! statInfo . isFile ( ) ) {
200211 throw new Error ( "Unable to create Resource: statInfo must represent either a file or a directory" ) ;
201212 }
202213 this . #byteSize ??= statInfo . size ;
203214 this . #lastModified ??= statInfo . mtimeMs ;
215+ this . #inode ??= statInfo . ino ;
204216
205217 // Create legacy statInfo object
206218 this . #statInfo = parseStat ( statInfo ) ;
@@ -519,9 +531,12 @@ class Resource {
519531 this . #contendModified( ) ;
520532 }
521533
522- async getHash ( ) {
534+ async getIntegrity ( ) {
535+ if ( this . #integrity) {
536+ return this . #integrity;
537+ }
523538 if ( this . isDirectory ( ) ) {
524- throw new Error ( `Unable to calculate hash for directory resource: ${ this . #path} ` ) ;
539+ throw new Error ( `Unable to calculate integrity for directory resource: ${ this . #path} ` ) ;
525540 }
526541
527542 // First wait for new content if the current content is flagged as drained
@@ -536,27 +551,37 @@ class Resource {
536551
537552 switch ( this . #contentType) {
538553 case CONTENT_TYPES . BUFFER :
539- return ssri . fromData ( this . #content, SSRI_OPTIONS ) . toString ( ) ;
554+ this . #integrity = ssri . fromData ( this . #content, SSRI_OPTIONS ) . toString ( ) ;
555+ break ;
540556 case CONTENT_TYPES . FACTORY :
541- return ( await ssri . fromStream ( this . #createStreamFactory( ) , SSRI_OPTIONS ) ) . toString ( ) ;
557+ if ( this . #createBufferFactory) {
558+ const buffer = await this . #getBufferFromFactory( this . #createBufferFactory) ;
559+ this . #integrity = ssri . fromData ( buffer , SSRI_OPTIONS ) . toString ( ) ;
560+ } else {
561+ this . #integrity = ( await ssri . fromStream ( this . #createStreamFactory( ) , SSRI_OPTIONS ) ) . toString ( ) ;
562+ }
563+ break ;
542564 case CONTENT_TYPES . STREAM :
543565 // To be discussed: Should we read the stream into a buffer here (using #getBufferFromStream) to avoid
544566 // draining it?
545- return ( await ssri . fromStream ( this . #getStream( ) , SSRI_OPTIONS ) ) . toString ( ) ;
567+ this . #integrity = ssri . fromData ( await this . #getBufferFromStream( this . #content) , SSRI_OPTIONS ) . toString ( ) ;
568+ break ;
546569 case CONTENT_TYPES . DRAINED_STREAM :
547570 throw new Error ( `Unexpected error: Content of Resource ${ this . #path} is flagged as drained.` ) ;
548571 case CONTENT_TYPES . IN_TRANSFORMATION :
549572 throw new Error ( `Unexpected error: Content of Resource ${ this . #path} is currently being transformed` ) ;
550573 default :
551574 throw new Error ( `Resource ${ this . #path} has no content` ) ;
552575 }
576+ return this . #integrity;
553577 }
554578
555579 #contendModified( ) {
556580 this . #sourceMetadata. contentModified = true ;
557581 this . #isModified = true ;
558582
559583 this . #byteSize = undefined ;
584+ this . #integrity = undefined ;
560585 this . #lastModified = new Date ( ) . getTime ( ) ; // TODO: Always update or keep initial value (= fs stat)?
561586
562587 if ( this . #contentType === CONTENT_TYPES . BUFFER ) {
@@ -682,6 +707,16 @@ class Resource {
682707 return this . #lastModified;
683708 }
684709
710+ /**
711+ * Gets the inode number of the resource.
712+ *
713+ * @public
714+ * @returns {number } Inode number of the resource
715+ */
716+ getInode ( ) {
717+ return this . #inode;
718+ }
719+
685720 /**
686721 * Resource content size in bytes.
687722 *
@@ -753,6 +788,7 @@ class Resource {
753788 isDirectory : this . #isDirectory,
754789 byteSize : this . #byteSize,
755790 lastModified : this . #lastModified,
791+ integrity : this . #isDirectory ? undefined : ( this . #contentType ? await this . getIntegrity ( ) : undefined ) ,
756792 sourceMetadata : clone ( this . #sourceMetadata)
757793 } ;
758794
0 commit comments