Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #24 -- Move config to pyproject.toml #25

Merged
merged 4 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,23 @@ INSTALLED_APPS = [
]
```

### 2. Create an `importmap.toml` file
### 2. Configuring an import map

This should live next to your `manage.py` file.
Here you'll add a list of "packages" you want to use.
You JavaScript dependencies are conveniently located in your`pyproject.toml` file.

The "name" can be anything, but should probably be the same as what it you would import from in typical bundling setups (i.e. `import React from "react"`).

The "source" will get passed on to the [jspm.org generator](https://jspm.org/docs/api#install), but is basically the `<npm package>@<version>` you want to use.
They are listed under `[tool.importmap.dependencies]` and you can add them there. The format is `name = "version"`,
similar to how you would add a dependency to your `package.json` file.

```toml
[[packages]]
name = "react"
source = "[email protected]"
# pyproject.toml
[tool.importmap.dependencies]
react = "17.0.2"
react-dom = "17.0.2"
```

[jspm.org generator](https://jspm.org/docs/api#install) is used lock and serve the dependencies,
but is basically just like installing them via `npm i <npm package>@<version>`.

### 3. Run `importmap_generate`

To resolve the import map, you'll need to run `python manage.py importmap_generate`.
Expand Down
59 changes: 17 additions & 42 deletions importmap/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,22 @@
import json
import logging
import os
from pathlib import Path

import tomli
from marshmallow import Schema, fields
try:
import tomllib
except ImportError:
import tomli as tomllib

from .generator import ImportmapGenerator

logger = logging.getLogger(__name__)


DEFAULT_CONFIG_FILENAME = "importmap.toml"
DEFAULT_CONFIG_FILENAME = "pyproject.toml"
DEFAULT_LOCK_FILENAME = "importmap.lock"


class PackageSchema(Schema):
name = fields.String(required=True)
source = fields.String(required=True)
# preload
# vendor, or vendor all is one option?


class ConfigSchema(Schema):
packages = fields.List(fields.Nested(PackageSchema), required=True)


class LockfileSchema(Schema):
config_hash = fields.String(required=True)
importmap = fields.Dict(required=True)
importmap_dev = fields.Dict(required=True)


def hash_for_data(data):
return hashlib.md5(json.dumps(data, sort_keys=True).encode("utf-8")).hexdigest()

Expand All @@ -42,8 +28,8 @@ def __init__(
config_filename=DEFAULT_CONFIG_FILENAME,
lock_filename=DEFAULT_LOCK_FILENAME,
):
self.config_filename = config_filename
self.lock_filename = lock_filename
self.config_file = Path(config_filename)
self.lock_file = Path(lock_filename)
self.load()

@classmethod
Expand All @@ -70,7 +56,7 @@ def load(self):
# No config = no map and no lockfile
self.map = {}
self.map_dev = {}
self.delete_lockfile()
self.lock_file.unlink(missing_ok=True)
return

lockfile = self.load_lockfile()
Expand All @@ -95,34 +81,23 @@ def generate(self, force=False):
self.save_lockfile(lockfile)

def load_config(self):
# TODO raise custom exceptions

if not os.path.exists(self.config_filename):
logger.warning(f"{self.config_filename} not found")
if not self.config_file.exists():
return {}
with self.config_file.open("rb") as f:
pyproject = tomllib.load(f)

with open(self.config_filename, "r") as f:
# why doesn't tomli.load(f) work?
toml_data = tomli.loads(f.read())

return ConfigSchema().load(toml_data)
return pyproject["tool"]["importmap"]

def load_lockfile(self):
if not os.path.exists(self.lock_filename):
if not self.lock_file.exists():
return {}

with open(self.lock_filename, "r") as f:
json_data = json.load(f)

return LockfileSchema().load(json_data)
with self.lock_file.open("r") as f:
return json.load(f)

def save_lockfile(self, lockfile):
with open(self.lock_filename, "w+") as f:
with self.lock_file.open("w+") as f:
json.dump(lockfile, f, indent=2, sort_keys=True)

def delete_lockfile(self):
if os.path.exists(self.lock_filename):
os.remove(self.lock_filename)

def generate_map(self, *args, **kwargs):
return ImportmapGenerator.from_config(self.config, *args, **kwargs).generate()
14 changes: 8 additions & 6 deletions importmap/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ def __init__(self, targets, development=False, provider="jspm"):

@classmethod
def from_config(cls, config, *args, **kwargs):
targets = []

for map in config["packages"]:
targets.append(map["source"])

return cls(targets, *args, **kwargs)
return cls(
[
f"{package}@{version}"
for package, version in config["dependencies"].items()
],
*args,
**kwargs,
)

def get_env(self):
if self.development:
Expand Down
Loading
Loading