Skip to content

Commit

Permalink
Add method generator and generated method docs to @aws-lite/s3
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanblock committed Sep 28, 2023
1 parent 3ba0a9d commit 0688947
Show file tree
Hide file tree
Showing 2 changed files with 277 additions and 52 deletions.
190 changes: 186 additions & 4 deletions plugins/s3/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,193 @@
npm i @aws-lite/s3
```

## Docs

<!-- ! Do not remove docs_start / docs_end ! -->
<!-- docs_start -->
<!-- docs_end -->
## Methods

<!-- ! Do not remove method_docs_start / method_docs_end ! -->
<!-- method_docs_start -->
### `PutObject`

[Canonical AWS API doc](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html)

Properties:
- **`Bucket` (string) [required]**
- S3 bucket name
- **`Key` (string) [required]**
- S3 key / file name
- **`File` (string) [required]**
- File path to be read and uploaded from the local filesystem
- **`MinChunkSize` (number)**
- Minimum size (in bytes) to utilize AWS-chunk-encoded uploads to S3
- **`ACL` (string)**
- Sets header: x-amz-acl
- **`BucketKeyEnabled` (string)**
- Sets header: x-amz-server-side-encryption-bucket-key-enabled
- **`CacheControl` (string)**
- Sets header: Cache-Control
- **`ChecksumAlgorithm` (string)**
- Sets header: x-amz-sdk-checksum-algorithm
- **`ChecksumCRC32` (string)**
- Sets header: x-amz-checksum-crc32
- **`ChecksumCRC32C` (string)**
- Sets header: x-amz-checksum-crc32c
- **`ChecksumSHA1` (string)**
- Sets header: x-amz-checksum-sha1
- **`ChecksumSHA256` (string)**
- Sets header: x-amz-checksum-sha256
- **`ContentDisposition` (string)**
- Sets header: Content-Disposition
- **`ContentEncoding` (string)**
- Sets header: Content-Encoding
- **`ContentLanguage` (string)**
- Sets header: Content-Language
- **`ContentLength` (string)**
- Sets header: Content-Length
- **`ContentMD5` (string)**
- Sets header: Content-MD5
- **`ContentType` (string)**
- Sets header: Content-Type
- **`ExpectedBucketOwner` (string)**
- Sets header: x-amz-expected-bucket-owner
- **`Expires` (string)**
- Sets header: Expires
- **`GrantFullControl` (string)**
- Sets header: x-amz-grant-full-control
- **`GrantRead` (string)**
- Sets header: x-amz-grant-read
- **`GrantReadACP` (string)**
- Sets header: x-amz-grant-read-acp
- **`GrantWriteACP` (string)**
- Sets header: x-amz-grant-write-acp
- **`ObjectLockLegalHoldStatus` (string)**
- Sets header: x-amz-object-lock-legal-hold
- **`ObjectLockMode` (string)**
- Sets header: x-amz-object-lock-mode
- **`ObjectLockRetainUntilDate` (string)**
- Sets header: x-amz-object-lock-retain-until-date
- **`RequestPayer` (string)**
- Sets header: x-amz-request-payer
- **`ServerSideEncryption` (string)**
- Sets header: x-amz-server-side-encryption
- **`SSECustomerAlgorithm` (string)**
- Sets header: x-amz-server-side-encryption-customer-algorithm
- **`SSECustomerKey` (string)**
- Sets header: x-amz-server-side-encryption-customer-key
- **`SSECustomerKeyMD5` (string)**
- Sets header: x-amz-server-side-encryption-customer-key-MD5
- **`SSEKMSEncryptionContext` (string)**
- Sets header: x-amz-server-side-encryption-context
- **`SSEKMSKeyId` (string)**
- Sets header: x-amz-server-side-encryption-aws-kms-key-id
- **`StorageClass` (string)**
- Sets header: x-amz-storage-class
- **`Tagging` (string)**
- Sets header: x-amz-tagging
- **`WebsiteRedirectLocation` (string)**
- Sets header: x-amz-website-redirect-location


### Methods yet to be implemented

> Please help out by [opening a PR](https://github.com/architect/aws-lite#authoring-aws-lite-plugins)!
- `AbortMultipartUpload`
- `CompleteMultipartUpload`
- `CopyObject`
- `CreateBucket`
- `CreateMultipartUpload`
- `DeleteBucket`
- `DeleteBucketAnalyticsConfiguration`
- `DeleteBucketCors`
- `DeleteBucketEncryption`
- `DeleteBucketIntelligentTieringConfiguration`
- `DeleteBucketInventoryConfiguration`
- `DeleteBucketLifecycle`
- `DeleteBucketMetricsConfiguration`
- `DeleteBucketOwnershipControls`
- `DeleteBucketPolicy`
- `DeleteBucketReplication`
- `DeleteBucketTagging`
- `DeleteBucketWebsite`
- `DeleteObject`
- `DeleteObjects`
- `DeleteObjectTagging`
- `DeletePublicAccessBlock`
- `GetBucketAccelerateConfiguration`
- `GetBucketAcl`
- `GetBucketAnalyticsConfiguration`
- `GetBucketCors`
- `GetBucketEncryption`
- `GetBucketIntelligentTieringConfiguration`
- `GetBucketInventoryConfiguration`
- `GetBucketLifecycle`
- `GetBucketLifecycleConfiguration`
- `GetBucketLocation`
- `GetBucketLogging`
- `GetBucketMetricsConfiguration`
- `GetBucketNotification`
- `GetBucketNotificationConfiguration`
- `GetBucketOwnershipControls`
- `GetBucketPolicy`
- `GetBucketPolicyStatus`
- `GetBucketReplication`
- `GetBucketRequestPayment`
- `GetBucketTagging`
- `GetBucketVersioning`
- `GetBucketWebsite`
- `GetObject`
- `GetObjectAcl`
- `GetObjectAttributes`
- `GetObjectLegalHold`
- `GetObjectLockConfiguration`
- `GetObjectRetention`
- `GetObjectTagging`
- `GetObjectTorrent`
- `GetPublicAccessBlock`
- `HeadBucket`
- `HeadObject`
- `ListBucketAnalyticsConfigurations`
- `ListBucketIntelligentTieringConfigurations`
- `ListBucketInventoryConfigurations`
- `ListBucketMetricsConfigurations`
- `ListBuckets`
- `ListMultipartUploads`
- `ListObjects`
- `ListObjectsV2`
- `ListObjectVersions`
- `ListParts`
- `PutBucketAccelerateConfiguration`
- `PutBucketAcl`
- `PutBucketAnalyticsConfiguration`
- `PutBucketCors`
- `PutBucketEncryption`
- `PutBucketIntelligentTieringConfiguration`
- `PutBucketInventoryConfiguration`
- `PutBucketLifecycle`
- `PutBucketLifecycleConfiguration`
- `PutBucketLogging`
- `PutBucketMetricsConfiguration`
- `PutBucketNotification`
- `PutBucketNotificationConfiguration`
- `PutBucketOwnershipControls`
- `PutBucketPolicy`
- `PutBucketReplication`
- `PutBucketRequestPayment`
- `PutBucketTagging`
- `PutBucketVersioning`
- `PutBucketWebsite`
- `PutObjectAcl`
- `PutObjectLegalHold`
- `PutObjectLockConfiguration`
- `PutObjectRetention`
- `PutObjectTagging`
- `PutPublicAccessBlock`
- `RestoreObject`
- `SelectObjectContent`
- `UploadPart`
- `UploadPartCopy`
- `WriteGetObjectResponse`
<!-- method_docs_end -->


## Learn more
Expand Down
139 changes: 91 additions & 48 deletions scripts/generate-plugins/index.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#! /usr/bin/env node
import { join } from 'node:path'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'

const cwd = process.cwd()
const pluginListRegex = /(?<=(<!-- plugins_start -->\n))[\s\S]*?(?=(<!-- plugins_end -->))/g
const pluginMethodsRegex = /(?<=(<!-- method_docs_start -->\n))[\s\S]*?(?=(<!-- method_docs_end -->))/g

// Break this into a separate file if it becomes too big / unwieldy!
// - name: the official service name; example: `cloudformation`
Expand All @@ -15,60 +18,100 @@ const pluginTmpl = readFileSync(join(cwd, 'scripts', 'generate-plugins', '_plugi
const readmeTmpl = readFileSync(join(cwd, 'scripts', 'generate-plugins', '_readme-tmpl.md')).toString()
const packageTmpl = readFileSync(join(cwd, 'scripts', 'generate-plugins', '_package-tmpl.json'))

plugins.forEach(plugin => {
if (!plugin.name || typeof plugin.name !== 'string' ||
!plugin.service || typeof plugin.service !== 'string' ||
!plugin.maintainers || !Array.isArray(plugin.maintainers)) {
throw ReferenceError(`Specified plugin must have 'name' (string), 'service' (string), and 'maintainers' (array)`)
}

let pluginDir = join(cwd, 'plugins', plugin.name)
let maintainers = plugin.maintainers.join(', ')
if (!existsSync(pluginDir)) {
let pluginSrc = join(pluginDir, 'src')
mkdirSync(pluginSrc, { recursive: true })
async function main () {
for (let plugin of plugins) {
if (!plugin.name || typeof plugin.name !== 'string' ||
!plugin.service || typeof plugin.service !== 'string' ||
!plugin.maintainers || !Array.isArray(plugin.maintainers)) {
throw ReferenceError(`Specified plugin must have 'name' (string), 'service' (string), and 'maintainers' (array)`)
}

let name = `@aws-lite/${plugin.name}`
let desc = `Official \`aws-lite\` plugin for ${plugin.service}`
let pluginDir = join(cwd, 'plugins', plugin.name)
let maintainers = plugin.maintainers.join(', ')
if (!existsSync(pluginDir)) {
let pluginSrc = join(pluginDir, 'src')
mkdirSync(pluginSrc, { recursive: true })

// Plugin: src/index.js
let src = pluginTmpl
.replace(/\$NAME/g, plugin.name)
.replace(/\$MAINTAINERS/g, maintainers)
writeFileSync(join(pluginSrc, 'index.mjs'), src)
let desc = `Official \`aws-lite\` plugin for ${plugin.service}`

// Plugin: package.json
let pkg = JSON.parse(packageTmpl)
pkg.name = name
pkg.description = desc
pkg.author = maintainers
pkg.repository.directory = `plugins/${plugin.name}`
writeFileSync(join(pluginDir, 'package.json'), JSON.stringify(pkg, null, 2))
// Plugin: src/index.js
let src = pluginTmpl
.replace(/\$NAME/g, plugin.name)
.replace(/\$MAINTAINERS/g, maintainers)
writeFileSync(join(pluginSrc, 'index.mjs'), src)

// Plugin: package.json
let pkg = JSON.parse(packageTmpl)
pkg.name = name
pkg.description = desc
pkg.author = maintainers
pkg.repository.directory = `plugins/${plugin.name}`
writeFileSync(join(pluginDir, 'package.json'), JSON.stringify(pkg, null, 2))

// Plugin: readme.md
let maintainerLinks = plugin.maintainers.map(p => `[${p}](https://github.com/${p.replace('@', '')})`).join(', ')
let readme = readmeTmpl
.replace(/\$NAME/g, name)
.replace(/\$DESC/g, desc)
.replace(/\$MAINTAINERS/g, maintainerLinks)
writeFileSync(join(pluginDir, 'readme.md'), readme)

// Project: package.json
let projectPkgFile = join(cwd, 'package.json')
let projectPkg = JSON.parse(readFileSync(projectPkgFile))
let workspace = `plugins/${plugin.name}`
if (!projectPkg.workspaces.includes(workspace)) {
projectPkg.workspaces.push(workspace)
projectPkg.workspaces = projectPkg.workspaces.sort()
writeFileSync(projectPkgFile, JSON.stringify(projectPkg, null, 2))
}
}
// Maybe update docs
else {
// TODO ↓ remove once things are nice and dialed in! ↓
if (plugin.name !== 's3') continue

// Plugin: readme.md
let maintainerLinks = plugin.maintainers.map(p => `[${p}](https://github.com/${p.replace('@', '')})`).join(', ')
let readme = readmeTmpl
.replace(/\$NAME/g, name)
.replace(/\$DESC/g, desc)
.replace(/\$MAINTAINERS/g, maintainerLinks)
writeFileSync(join(pluginDir, 'readme.md'), readme)
const pluginReadmeFile = join(pluginDir, 'readme.md')
let pluginReadme = readFileSync(pluginReadmeFile).toString()
// Generate docs markdown
const { default: _plugin } = await import(name)
let incompleteMethods = []
let methodDocs = Object.keys(_plugin.methods).map(methodName => {
let header = `### \`${methodName}\`\n\n`
if (!_plugin.methods[methodName] || _plugin.methods[methodName].disabled) {
incompleteMethods.push(methodName)
return
}
const { awsDoc, validate } = _plugin.methods[methodName]
if (!awsDoc) throw ReferenceError(`All methods must refer to an AWS service API doc: ${name} ${methodName}`)
header += `[Canonical AWS API doc](${awsDoc})\n`
if (validate) {
header += `\nProperties:\n` + Object.entries(validate).map(([ param, values ]) => {
const { type, required, comment } = values
const _req = required ? ' [required]' : ''
const _com = comment ? `\n - ${comment}` : ''
return `- **\`${param}\` (${type})${_req}**${_com}`
}).join('\n')
}
return header
}).filter(Boolean).join('\n\n\n') + '\n'

// Project: package.json
let projectPkgFile = join(cwd, 'package.json')
let projectPkg = JSON.parse(readFileSync(projectPkgFile))
let workspace = `plugins/${plugin.name}`
if (!projectPkg.workspaces.includes(workspace)) {
projectPkg.workspaces.push(workspace)
projectPkg.workspaces = projectPkg.workspaces.sort()
writeFileSync(projectPkgFile, JSON.stringify(projectPkg, null, 2))
if (incompleteMethods.length) {
methodDocs += `\n\n### Methods yet to be implemented\n\n` +
`> Please help out by [opening a PR](https://github.com/architect/aws-lite#authoring-aws-lite-plugins)!\n\n` +
incompleteMethods.map(methodName => `- \`${methodName}\``).join('\n') + '\n'
}
pluginReadme = pluginReadme.replace(pluginMethodsRegex, methodDocs)
writeFileSync(pluginReadmeFile, pluginReadme)
}
}
})

// Project readme.md
let projectReadmeFile = join(cwd, 'readme.md')
let projectReadme = readFileSync(projectReadmeFile).toString()
let pluginListRegex = /(?<=(<!-- plugins_start -->\n))[\s\S]*?(?=(<!-- plugins_end -->))/g
let pluginList = plugins.map(({ name, service }) => `- [${service}](https://www.npmjs.com/package/@aws-lite/${name})`)
projectReadme = projectReadme.replace(pluginListRegex, pluginList.join('\n') + '\n')
writeFileSync(projectReadmeFile, projectReadme)
// Project readme.md
const projectReadmeFile = join(cwd, 'readme.md')
let projectReadme = readFileSync(projectReadmeFile).toString()
const pluginList = plugins.map(({ name, service }) => `- [${service}](https://www.npmjs.com/package/@aws-lite/${name})`)
projectReadme = projectReadme.replace(pluginListRegex, pluginList.join('\n') + '\n')
writeFileSync(projectReadmeFile, projectReadme)
}
main()

0 comments on commit 0688947

Please sign in to comment.