Skip to content

Commit

Permalink
Merge pull request #3 from jollytoad/jsr
Browse files Browse the repository at this point in the history
JSR
  • Loading branch information
jollytoad committed Jun 27, 2024
2 parents 059ce51 + a092ec7 commit 19ead57
Show file tree
Hide file tree
Showing 21 changed files with 474 additions and 147 deletions.
63 changes: 30 additions & 33 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,41 +1,38 @@
name: ci

on: [push, pull_request]
on:
push:
branches:
- main
pull_request:
branches:
- main

permissions:
contents: read

jobs:
deno:
name: deno_import_content-${{ matrix.os }}
if: |
github.event_name == 'push' ||
!startsWith(github.event.pull_request.head.label, 'denoland:')
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
matrix:
os: [macOS-latest, ubuntu-latest, windows-2019]

env:
GH_ACTIONS: 1
test:
runs-on: ubuntu-latest

steps:
- name: ☑️ clone repository
uses: actions/checkout@v2
- name: Checkout
uses: actions/checkout@v4

- name: ➡️ install Deno
- name: Install Deno
uses: denoland/setup-deno@v1
with:
deno-version: v1.x

- name: 💄 format
if: contains(matrix.os, 'ubuntu')
run: |
deno fmt --check
- name: 💄 lint
if: contains(matrix.os, 'ubuntu')
run: |
deno lint
- name: 🧪 test
run: |
deno task test

- name: Verify formatting
run: deno fmt --check

- name: Run linter
run: deno task lint

- name: Run TypeScript checking
run: deno task check

- name: Run tests
run: deno task test

- name: Publish dry run
run: deno publish --dry-run
27 changes: 27 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Publish

on:
workflow_run:
workflows: [ci]
types: [completed]
branches: [main]

jobs:
publish:
runs-on: ubuntu-latest

if: ${{ github.event.workflow_run.conclusion == 'success' }}

permissions:
contents: read
id-token: write

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Deno
uses: denoland/setup-deno@v1

- name: Publish package
run: deno publish
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
.vscode
deno.lock
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.0]

### Added

- `importBlob()` to import a binary file as a
[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
- `importBinary()` to import a binary file as a
[Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)

## [1.0.0]

- Initial release of `importText()` function.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Mark Gibson
Copyright (c) 2024 Mark Gibson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
39 changes: 23 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
# deno_import_content

[![deno doc](https://doc.deno.land/badge.svg)](https://deno.land/x/import_content/mod.ts)
# Deno Import Content

Import arbitrary file content in Deno using module resolution algorithms.

This includes resolving via an import map, authentication using
`DENO_AUTH_TOKENS`, and use of the Deno cache.

The idea is that `importText()` should act as similar to dynamic `import()` as
possible, but just returning the raw text content instead of an evaluated JS or
TS module.
The idea is that `importText()`/`importBlob()`/`importBinary()` should act as
similar to dynamic `import()` as possible, but just returning the raw text or
binary content instead of an evaluated JS or TS module.

Unfortunately it's not possible for `importText` to resolve a relative specifier
against the calling module, so they will need to be pre-resolved using
Unfortunately it's not possible for these functions to resolve a relative
specifier against the calling module, so they will need to be pre-resolved using
`import.meta.resolve()`. (See the example below, and the tests)

If anyone knows how we could get around this, please raise an issue or better
still, a PR.

## Permissions

This module makes use of [`deno_cache`](https://deno.land/x/deno_cache) to
perform fetching, and therefore requires all permissions that it requires. See
those [docs](https://deno.land/x/deno_cache#permissions) for full details.
This module makes use of [`@deno/cache-dir`](https://jsr.io/@deno/cache-dir) to
perform fetching, and therefore requires all permissions that it requires.

Although, `--allow-write` permission for the cache dir is optional. If it is
granted, then remote content will be cached, otherwise it will be fetched every
Expand All @@ -31,7 +28,7 @@ time if the content isn't already present in the cache.
## Example

```ts
import { importText } from "https://deno.land/x/import_content/mod.ts";
import { importText } from "jsr:@jollytoad/import-content";

// Fetch the text content of a remote file
const remoteReadme = await importText(
Expand All @@ -45,8 +42,18 @@ const localReadme = await importText(import.meta.resolve("./README.md"));
const mappedReadme = await importText("bare/README.md");
```

## Fixed Dependencies
## Planned Obsolescence

Hopefully this entire package will become completely obsolete once Deno fully
supports importing of arbitrary files via import attributes...

```ts
const remoteReadme = await import(
"https://deno.land/x/import_content/README.md",
{ with: { type: "text" } }
);

const localReadme = await import("./README.md", { with: { type: "text" } });

Previous versions of this module depended on my patched version of `deno_cache`,
due to bugs in that module. These have since been fixed, so this module now
depends on the official [`deno_cache`](https://deno.land/x/[email protected]).
const mappedReadme = await import("bare/README.md", { with: { type: "text" } });
```
29 changes: 27 additions & 2 deletions deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
{
"name": "@jollytoad/import-content",
"version": "1.1.0",
"exports": {
".": "./mod.ts",
"./import-text": "./import_text.ts",
"./import-binary": "./import_binary.ts",
"./import-blob": "./import_blob.ts"
},
"tasks": {
"test": "deno test --allow-read --allow-write --allow-net --allow-env --import-map=test/import_map.json",
"check": "deno fmt && deno lint && deno check **/*.ts"
"test": "deno test --allow-read --allow-write --allow-net --allow-env",
"check": "deno check **/*.ts",
"lint": "deno lint && deno doc --lint **/*.ts",
"ok": "deno fmt && deno task lint && deno task check && deno task test && deno publish --dry-run --allow-dirty",
"outdated": "deno run --allow-read=. --allow-net=jsr.io,registry.npmjs.org jsr:@check/deps",
"lock": "rm -f deno.lock && deno task check"
},
"imports": {
"$test/": "http://localhost:8910/",
"@deno/cache-dir": "jsr:@deno/cache-dir@^0.10.1",
"@http/host-deno-local": "jsr:@http/host-deno-local@^0.18.0",
"@std/assert": "jsr:@std/assert@^1.0.0-rc.2",
"@std/ulid": "jsr:@std/ulid@^1.0.0-rc.2"
},
"publish": {
"exclude": [
".github",
"deno.lock"
]
}
}
83 changes: 83 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions deps.ts

This file was deleted.

56 changes: 56 additions & 0 deletions file_fetcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { DenoDir, FileFetcher } from "@deno/cache-dir";

let fileFetcher: FileFetcher | undefined;

/**
* INTERNAL: For test usage only
* @private
* @deprecated
*/
export function __reset__() {
fileFetcher = undefined;
}

/**
* Get a cached instance of the FileFetcher
*/
async function getFileFetcher() {
if (!fileFetcher) {
const denoDir = new DenoDir();
const writeGranted =
(await Deno.permissions.query({ name: "write", path: denoDir.root }))
.state === "granted";
fileFetcher = new FileFetcher(() =>
denoDir.createHttpCache({ readOnly: !writeGranted })
);
}
return fileFetcher;
}

/**
* Fetch the file using the FileFetcher
*/
export async function fetchFile(
specifier: string,
): Promise<string | Uint8Array> {
const fileFetcher = await getFileFetcher();

if (isRelative(specifier)) {
throw new TypeError(
`Cannot import a relative module "${specifier}", use import.meta.resolve() to first resolve to an absolute URL.`,
);
}

const resolved = new URL(import.meta.resolve(specifier));
const response = await fileFetcher.fetch(resolved);

if (response?.kind === "module") {
return response.content;
} else {
throw new TypeError(`Module content not found "${specifier.toString()}".`);
}
}

function isRelative(specifier: string) {
return specifier.startsWith("./") || specifier.startsWith("../");
}
17 changes: 17 additions & 0 deletions import_binary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { fetchFile } from "./file_fetcher.ts";

/**
* Import an arbitrary binary file via a Deno module specifier, as similar to a dynamic `import()`
* as possible, but just returns the binary content rather than evaluating it as a JS/TS module.
*
* @param specifier An absolute URL, or bare module specifier, but not a relative URL, use import.meta.resolve(),
* to first resolve those to an absolute URL. Can be to any file, not just JS/TS,
* @returns The content of the file as a Uint8Array.
*/
export async function importBinary(specifier: string): Promise<Uint8Array> {
const content = await fetchFile(specifier);

return typeof content === "string"
? new TextEncoder().encode(content)
: content;
}
Loading

0 comments on commit 19ead57

Please sign in to comment.