markdown

package
v1.0.23 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var MarkdownCreate = common.Shortcut{
	Service:     "markdown",
	Command:     "+create",
	Description: "Create a Markdown file in Drive",
	Risk:        "write",
	Scopes:      []string{"drive:file:upload"},
	AuthTypes:   []string{"user", "bot"},
	HasFormat:   true,
	Flags: []common.Flag{
		{Name: "folder-token", Desc: "target Drive folder token (default: root folder)"},
		{Name: "name", Desc: "file name with .md suffix; required with --content, optional with --file"},
		{Name: "content", Desc: "Markdown content", Input: []string{common.File, common.Stdin}},
		{Name: "file", Desc: "local .md file path"},
	},
	Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
		return validateMarkdownSpec(runtime, markdownUploadSpec{
			FileName:    strings.TrimSpace(runtime.Str("name")),
			FolderToken: strings.TrimSpace(runtime.Str("folder-token")),
			FilePath:    strings.TrimSpace(runtime.Str("file")),
			FileSet:     runtime.Changed("file"),
			Content:     runtime.Str("content"),
			ContentSet:  runtime.Changed("content"),
		}, true)
	},
	DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
		spec := markdownUploadSpec{
			FileName:    strings.TrimSpace(runtime.Str("name")),
			FolderToken: strings.TrimSpace(runtime.Str("folder-token")),
			FilePath:    strings.TrimSpace(runtime.Str("file")),
			FileSet:     runtime.Changed("file"),
			Content:     runtime.Str("content"),
			ContentSet:  runtime.Changed("content"),
		}
		fileSize, err := markdownSourceSize(runtime, spec)
		if err != nil {
			return common.NewDryRunAPI().Set("error", err.Error())
		}
		return markdownUploadDryRun(spec, fileSize, fileSize > markdownSinglePartSizeLimit)
	},
	Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
		spec := markdownUploadSpec{
			FileName:    strings.TrimSpace(runtime.Str("name")),
			FolderToken: strings.TrimSpace(runtime.Str("folder-token")),
			FilePath:    strings.TrimSpace(runtime.Str("file")),
			FileSet:     runtime.Changed("file"),
			Content:     runtime.Str("content"),
			ContentSet:  runtime.Changed("content"),
		}
		fileSize, err := markdownSourceSize(runtime, spec)
		if err != nil {
			return err
		}

		var result markdownUploadResult
		if spec.FileSet {
			result, err = uploadMarkdownLocalFile(runtime, spec, fileSize)
		} else {
			result, err = uploadMarkdownContent(runtime, spec, []byte(spec.Content))
		}
		if err != nil {
			return err
		}

		out := map[string]interface{}{
			"file_token": result.FileToken,
			"file_name":  finalMarkdownFileName(spec),
			"size_bytes": fileSize,
		}
		if grant := common.AutoGrantCurrentUserDrivePermission(runtime, result.FileToken, "file"); grant != nil {
			out["permission_grant"] = grant
		}

		runtime.OutFormat(out, nil, func(w io.Writer) {
			prettyPrintMarkdownWrite(w, out)
		})
		return nil
	},
}
View Source
var MarkdownFetch = common.Shortcut{
	Service:     "markdown",
	Command:     "+fetch",
	Description: "Fetch a Markdown file from Drive",
	Risk:        "read",
	Scopes:      []string{"drive:file:download"},
	AuthTypes:   []string{"user", "bot"},
	HasFormat:   true,
	Flags: []common.Flag{
		{Name: "file-token", Desc: "Markdown file token", Required: true},
		{Name: "output", Desc: "local save path or directory; omit to return content directly"},
		{Name: "overwrite", Type: "bool", Desc: "overwrite existing local output file"},
	},
	Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
		fileToken := strings.TrimSpace(runtime.Str("file-token"))
		if err := validate.ResourceName(fileToken, "--file-token"); err != nil {
			return output.ErrValidation("%s", err)
		}
		outputPath := strings.TrimSpace(runtime.Str("output"))
		if outputPath == "" {
			return nil
		}
		if _, err := validate.SafeOutputPath(outputPath); err != nil {
			return output.ErrValidation("unsafe output path: %s", err)
		}
		return nil
	},
	DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
		dry := common.NewDryRunAPI().
			Desc("download markdown file bytes; when --output is omitted the CLI returns content as UTF-8 text").
			GET("/open-apis/drive/v1/files/:file_token/download").
			Set("file_token", runtime.Str("file-token"))
		if outputPath := strings.TrimSpace(runtime.Str("output")); outputPath != "" {
			dry.Set("output", outputPath)
		} else {
			dry.Set("output", "<stdout>")
		}
		return dry
	},
	Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
		fileToken := strings.TrimSpace(runtime.Str("file-token"))
		outputPath := strings.TrimSpace(runtime.Str("output"))

		resp, err := runtime.DoAPIStream(ctx, &larkcore.ApiReq{
			HttpMethod: http.MethodGet,
			ApiPath:    fmt.Sprintf("/open-apis/drive/v1/files/%s/download", validate.EncodePathSegment(fileToken)),
		})
		if err != nil {
			return output.ErrNetwork("download failed: %s", err)
		}
		defer resp.Body.Close()

		fileName := fileNameFromDownloadHeader(resp.Header, fileToken+".md")
		if outputPath == "" {
			payload, err := io.ReadAll(resp.Body)
			if err != nil {
				return output.ErrNetwork("download failed: %s", err)
			}
			out := map[string]interface{}{
				"file_token": fileToken,
				"file_name":  fileName,
				"content":    string(payload),
				"size_bytes": len(payload),
			}
			runtime.OutFormatRaw(out, nil, func(w io.Writer) {
				prettyPrintMarkdownContent(w, out)
			})
			return nil
		}

		if markdownFetchOutputIsDirectory(runtime, outputPath) {
			outputPath = filepath.Join(outputPath, fileName)
		}
		if _, statErr := runtime.FileIO().Stat(outputPath); statErr == nil && !runtime.Bool("overwrite") {
			return output.ErrValidation("output file already exists: %s (use --overwrite to replace)", outputPath)
		}

		result, err := runtime.FileIO().Save(outputPath, fileio.SaveOptions{
			ContentType:   resp.Header.Get("Content-Type"),
			ContentLength: resp.ContentLength,
		}, resp.Body)
		if err != nil {
			return common.WrapSaveErrorByCategory(err, "io")
		}

		savedPath, _ := runtime.ResolveSavePath(outputPath)
		if savedPath == "" {
			savedPath = outputPath
		}

		out := map[string]interface{}{
			"file_token": fileToken,
			"file_name":  fileName,
			"saved_path": savedPath,
			"size_bytes": result.Size(),
		}
		runtime.OutFormat(out, nil, func(w io.Writer) {
			prettyPrintMarkdownSavedFile(w, out)
		})
		return nil
	},
}
View Source
var MarkdownOverwrite = common.Shortcut{
	Service:     "markdown",
	Command:     "+overwrite",
	Description: "Overwrite an existing Markdown file in Drive",
	Risk:        "write",
	Scopes:      []string{"drive:file:upload", "drive:drive.metadata:readonly"},
	AuthTypes:   []string{"user", "bot"},
	HasFormat:   true,
	Flags: []common.Flag{
		{Name: "file-token", Desc: "target Markdown file token", Required: true},
		{Name: "name", Desc: "optional file name with .md suffix; overrides the existing/local file name"},
		{Name: "content", Desc: "new Markdown content", Input: []string{common.File, common.Stdin}},
		{Name: "file", Desc: "local .md file path"},
	},
	Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
		fileToken := strings.TrimSpace(runtime.Str("file-token"))
		if err := validate.ResourceName(fileToken, "--file-token"); err != nil {
			return output.ErrValidation("%s", err)
		}
		return validateMarkdownSpec(runtime, markdownUploadSpec{
			FileToken:  fileToken,
			FileName:   strings.TrimSpace(runtime.Str("name")),
			FilePath:   strings.TrimSpace(runtime.Str("file")),
			FileSet:    runtime.Changed("file"),
			Content:    runtime.Str("content"),
			ContentSet: runtime.Changed("content"),
		}, false)
	},
	DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
		spec := markdownUploadSpec{
			FileToken:  strings.TrimSpace(runtime.Str("file-token")),
			FileName:   strings.TrimSpace(runtime.Str("name")),
			FilePath:   strings.TrimSpace(runtime.Str("file")),
			FileSet:    runtime.Changed("file"),
			Content:    runtime.Str("content"),
			ContentSet: runtime.Changed("content"),
		}
		fileSize, err := markdownSourceSize(runtime, spec)
		if err != nil {
			return common.NewDryRunAPI().Set("error", err.Error())
		}
		return markdownOverwriteDryRun(spec, fileSize, fileSize > markdownSinglePartSizeLimit)
	},
	Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
		fileToken := strings.TrimSpace(runtime.Str("file-token"))
		spec := markdownUploadSpec{
			FileToken:  fileToken,
			FileName:   strings.TrimSpace(runtime.Str("name")),
			FilePath:   strings.TrimSpace(runtime.Str("file")),
			FileSet:    runtime.Changed("file"),
			Content:    runtime.Str("content"),
			ContentSet: runtime.Changed("content"),
		}

		fileSize, err := markdownSourceSize(runtime, spec)
		if err != nil {
			return err
		}

		fileName := strings.TrimSpace(spec.FileName)
		if fileName == "" && spec.FileSet {
			fileName = filepath.Base(spec.FilePath)
		}
		if fileName == "" {
			remoteName, err := fetchMarkdownFileName(runtime, fileToken)
			if err != nil {
				return err
			}
			fileName = strings.TrimSpace(remoteName)
		}
		if fileName == "" {
			fileName = fileToken + ".md"
		}
		spec.FileName = fileName

		var result markdownUploadResult
		if spec.FileSet {
			result, err = uploadMarkdownLocalFile(runtime, spec, fileSize)
		} else {
			result, err = uploadMarkdownContent(runtime, spec, []byte(spec.Content))
		}
		if err != nil {
			return err
		}

		out := map[string]interface{}{
			"file_token": result.FileToken,
			"file_name":  fileName,
			"version":    result.Version,
			"size_bytes": fileSize,
		}
		runtime.OutFormat(out, nil, func(w io.Writer) {
			prettyPrintMarkdownWrite(w, out)
		})
		return nil
	},
}

Functions

func Shortcuts

func Shortcuts() []common.Shortcut

Shortcuts returns all markdown shortcuts.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL