Compare commits

...

8 Commits

Author SHA1 Message Date
Riccardo Ferretti
88ae96cf25 v0.26.5 2025-02-21 13:09:18 +01:00
Riccardo Ferretti
acfd2e1fc1 Preparation for next release 2025-02-21 13:08:32 +01:00
Riccardo
6b02a87538 Web extension support for daily note (#1426)
* Using nodemon for watch task

* Added documentation and generator pattern to support getting some data from multiple sources

* asAbsoluteUrl can now take URI or string

* Tweaked daily note computation

* Replacing URI.withFragment with generic URI.with

* Removed URI.file from non-testing code

* fixed asAbsoluteUri

* Various tweaks and fixes

* Fixed create-note command
2025-02-21 13:07:00 +01:00
allcontributors[bot]
1a99e693df add n8layman as a contributor for code (#1425)
* update docs/index.md [skip ci]

* update readme.md [skip ci]

* update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2025-02-21 09:28:47 +01:00
Nathan Layman
dd467ce86f Add config argument to specify valid markdown flavors (#1424)
* Try and add in support for quarto wikilink autocomplete as in https://github.com/MilesMcBain/foam

* Try and add in support for quarto wikilink autocomplete as in https://github.com/MilesMcBain/foam but make it general based on a new config in settings.json, "foam.supportedLanguages". That should allow for rmarkdown files as well.

* remove package-lock.json in favor of yarn.lock
2025-02-21 09:27:46 +01:00
Riccardo
7d7446ef7e added reference to alias in documentation 2025-01-26 14:54:56 +01:00
allcontributors[bot]
6be4f002b8 add markschaver as a contributor for doc (#1416)
* update docs/index.md [skip ci]

* update readme.md [skip ci]

* update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2024-11-23 18:48:42 +01:00
Mark Schaver
bb6faee06d Edited command menu titles to make case consistent (#1415) 2024-11-23 18:48:07 +01:00
27 changed files with 397 additions and 31937 deletions

View File

@@ -1112,6 +1112,24 @@
"contributions": [
"doc"
]
},
{
"login": "markschaver",
"name": "Mark Schaver",
"avatar_url": "https://avatars.githubusercontent.com/u/7584?v=4",
"profile": "http://schaver.com/",
"contributions": [
"doc"
]
},
{
"login": "n8layman",
"name": "Nathan Layman",
"avatar_url": "https://avatars.githubusercontent.com/u/25353944?v=4",
"profile": "https://github.com/n8layman",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

23
.vscode/tasks.json vendored
View File

@@ -7,7 +7,28 @@
"label": "watch: foam-vscode",
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"problemMatcher": {
"owner": "typescript",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": [
{
"regexp": "^(.*?)\\((\\d+),(\\d+)\\):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"message": 4
}
],
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": ".*"
},
"endsPattern": {
"regexp": ".*"
}
}
},
"isBackground": true,
"presentation": {
"reveal": "always"

View File

@@ -263,6 +263,8 @@ If that sounds like something you're interested in, I'd love to have you along o
<tr>
<td align="center" valign="top" width="14.28%"><a href="http://www.hegghammer.com"><img src="https://avatars.githubusercontent.com/u/64712218?v=4?s=60" width="60px;" alt="Thomas Hegghammer"/><br /><sub><b>Thomas Hegghammer</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=Hegghammer" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PiotrAleksander"><img src="https://avatars.githubusercontent.com/u/6314591?v=4?s=60" width="60px;" alt="Piotr Mrzygłosz"/><br /><sub><b>Piotr Mrzygłosz</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=PiotrAleksander" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://schaver.com/"><img src="https://avatars.githubusercontent.com/u/7584?v=4?s=60" width="60px;" alt="Mark Schaver"/><br /><sub><b>Mark Schaver</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=markschaver" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/n8layman"><img src="https://avatars.githubusercontent.com/u/25353944?v=4?s=60" width="60px;" alt="Nathan Layman"/><br /><sub><b>Nathan Layman</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=n8layman" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -32,6 +32,7 @@ Some properties have special meaning for Foam:
| `title` | will assign the name to the note that you will see in the graph, regardless of the filename or the first heading (also see how to [[write-notes-in-foam]]) |
| `type` | can be used to style notes differently in the graph (also see [[graph-visualization]]). The default type for a document is `note` unless otherwise specified with this property. |
| `tags` | can be used to add tags to a note (see [[tags]]) |
| `alias` | can be used to add aliases to the note. an alias will show up in the link autocompletion |
For example:
@@ -40,7 +41,7 @@ For example:
title: "Note Title"
type: "daily-note"
tags: daily, funny, planning
alias: alias1, alias2
---
```

View File

@@ -4,5 +4,5 @@
],
"npmClient": "yarn",
"useWorkspaces": true,
"version": "0.26.4"
"version": "0.26.5"
}

31816
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,12 @@ All notable changes to the "foam-vscode" extension will be documented in this fi
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [0.26.5] - 2025-02-21
Fixes and Improvements:
- Improved handling of virtual FS URIs (#1426)
## [0.26.4] - 2024-11-12
Fixes and Improvements:

View File

@@ -8,7 +8,7 @@
"type": "git"
},
"homepage": "https://github.com/foambubble/foam",
"version": "0.26.4",
"version": "0.26.5",
"license": "MIT",
"publisher": "foam",
"engines": {
@@ -301,19 +301,19 @@
},
{
"command": "foam-vscode.update-graph",
"title": "Foam: Update graph"
"title": "Foam: Update Graph"
},
{
"command": "foam-vscode.set-log-level",
"title": "Foam: Set log level"
"title": "Foam: Set Log Level"
},
{
"command": "foam-vscode.show-graph",
"title": "Foam: Show graph"
"title": "Foam: Show Graph"
},
{
"command": "foam-vscode.update-wikilink-definitions",
"title": "Foam: Update wikilink definitions"
"title": "Foam: Update Wikilink Definitions"
},
{
"command": "foam-vscode.open-daily-note",
@@ -349,11 +349,11 @@
},
{
"command": "foam-vscode.convert-link-style-inplace",
"title": "Foam: convert link style in place"
"title": "Foam: Convert Link Style in Place"
},
{
"command": "foam-vscode.convert-link-style-incopy",
"title": "Foam: convert link format in copy"
"title": "Foam: Convert Link Format in Copy"
},
{
"command": "foam-vscode.views.orphans.group-by:folder",
@@ -457,6 +457,13 @@
"configuration": {
"title": "Foam",
"properties": {
"foam.supportedLanguages": {
"type": "array",
"default": [
"markdown"
],
"description": "List of languages to treat as Markdown-like documents."
},
"foam.completion.label": {
"type": "string",
"default": "path",
@@ -670,7 +677,7 @@
"test:e2e": "yarn test-setup && node ./out/test/run-tests.js --e2e",
"lint": "dts lint src",
"clean": "rimraf out",
"watch": "tsc --build ./tsconfig.json --watch",
"watch": "nodemon --watch 'src/**/*.ts' --exec 'yarn build' --ext ts",
"vscode:start-debugging": "yarn clean && yarn watch",
"package-extension": "npx vsce package --yarn",
"install-extension": "code --install-extension ./foam-vscode-$npm_package_version.vsix",
@@ -704,6 +711,7 @@
"jest-extended": "^3.2.3",
"markdown-it": "^12.0.4",
"micromatch": "^4.0.2",
"nodemon": "^3.1.7",
"rimraf": "^3.0.2",
"ts-jest": "^29.1.1",
"tslib": "^2.0.0",

View File

@@ -8,9 +8,9 @@ describe('Foam URI', () => {
const base = URI.file('/path/to/file.md');
test.each([
['https://www.google.com', URI.parse('https://www.google.com')],
['/path/to/a/file.md', URI.file('/path/to/a/file.md')],
['../relative/file.md', URI.file('/path/relative/file.md')],
['#section', base.withFragment('section')],
['/path/to/a/file.md', URI.parse('file:///path/to/a/file.md')],
['../relative/file.md', URI.parse('file:///path/relative/file.md')],
['#section', base.with({ fragment: 'section' })],
[
'../relative/file.md#section',
URI.parse('file:/path/relative/file.md#section'),

View File

@@ -58,6 +58,11 @@ export class URI {
});
}
/**
* @deprecated Will not work with web extension. Use only for testing.
* @param value the path to turn into a URI
* @returns the file URI
*/
static file(value: string): URI {
const [path, authority] = pathUtils.fromFsPath(value);
return new URI({ scheme: 'file', authority, path });
@@ -71,7 +76,7 @@ export class URI {
const uri = value instanceof URI ? value : URI.parse(value);
if (!uri.isAbsolute()) {
if (uri.scheme === 'file' || uri.scheme === 'placeholder') {
let newUri = this.withFragment(uri.fragment);
let newUri = this.with({ fragment: uri.fragment });
if (uri.path) {
newUri = (isDirectory ? newUri : newUri.getDirectory())
.joinPath(uri.path)
@@ -119,8 +124,20 @@ export class URI {
return new URI({ ...this, path });
}
withFragment(fragment: string): URI {
return new URI({ ...this, fragment });
with(change: {
scheme?: string;
authority?: string;
path?: string;
query?: string;
fragment?: string;
}): URI {
return new URI({
scheme: change.scheme ?? this.scheme,
authority: change.authority ?? this.authority,
path: change.path ?? this.path,
query: change.query ?? this.query,
fragment: change.fragment ?? this.fragment,
});
}
/**
@@ -380,12 +397,21 @@ function encodeURIComponentMinimal(path: string): string {
*
* TODO this probably needs to be moved to the workspace service
*/
export function asAbsoluteUri(uri: URI, baseFolders: URI[]): URI {
const path = uri.path;
if (pathUtils.isAbsolute(path)) {
return uri;
export function asAbsoluteUri(
uriOrPath: URI | string,
baseFolders: URI[]
): URI {
if (baseFolders.length === 0) {
throw new Error('At least one base folder needed to compute URI');
}
const path = uriOrPath instanceof URI ? uriOrPath.path : uriOrPath;
if (path.startsWith('/')) {
return uriOrPath instanceof URI ? uriOrPath : baseFolders[0].with({ path });
}
let tokens = path.split('/');
while (tokens[0].trim() === '') {
tokens.shift();
}
const firstDir = tokens[0];
if (baseFolders.length > 1) {
for (const folder of baseFolders) {

View File

@@ -126,9 +126,9 @@ describe('Identifier computation', () => {
});
const ws = new FoamWorkspace('.md').set(first).set(second).set(third);
expect(ws.getIdentifier(first.uri.withFragment('section name'))).toEqual(
'to/page-a#section name'
);
expect(
ws.getIdentifier(first.uri.with({ fragment: 'section name' }))
).toEqual('to/page-a#section name');
});
const needle = '/project/car/todo';

View File

@@ -175,7 +175,10 @@ export class FoamWorkspace implements IDisposable {
}
}
if (resource && fragment) {
resource = { ...resource, uri: resource.uri.withFragment(fragment) };
resource = {
...resource,
uri: resource.uri.with({ fragment: fragment }),
};
}
return resource ?? null;
}

View File

@@ -148,7 +148,7 @@ describe('Link resolution', () => {
const ws = createTestWorkspace().set(noteA).set(noteB);
expect(ws.resolveLink(noteA, noteA.links[0])).toEqual(
noteB.uri.withFragment('section')
noteB.uri.with({ fragment: 'section' })
);
});
@@ -163,7 +163,7 @@ describe('Link resolution', () => {
const ws = createTestWorkspace().set(noteA);
expect(ws.resolveLink(noteA, noteA.links[0])).toEqual(
noteA.uri.withFragment('section')
noteA.uri.with({ fragment: 'section' })
);
});

View File

@@ -76,7 +76,7 @@ export class MarkdownResourceProvider implements ResourceProvider {
URI.placeholder(target);
if (section) {
targetUri = targetUri.withFragment(section);
targetUri = targetUri.with({ fragment: section });
}
}
break;
@@ -93,7 +93,7 @@ export class MarkdownResourceProvider implements ResourceProvider {
workspace.find(path, resource.uri)?.uri ??
URI.placeholder(resource.uri.resolve(path).path);
if (section && !targetUri.isPlaceholder()) {
targetUri = targetUri.withFragment(section);
targetUri = targetUri.with({ fragment: section });
}
break;
}

View File

@@ -1,23 +1,85 @@
import sha1 from 'js-sha1';
/**
* Checks if a value is not null.
*
* @param value - The value to check.
* @returns True if the value is not null, otherwise false.
*/
export function isNotNull<T>(value: T | null): value is T {
return value != null;
}
/**
* Checks if a value is not null, undefined, or void.
*
* @param value - The value to check.
* @returns True if the value is not null, undefined, or void, otherwise false.
*/
export function isSome<T>(
value: T | null | undefined | void
): value is NonNullable<T> {
return value != null;
}
/**
* Checks if a value is null, undefined, or void.
*
* @param value - The value to check.
* @returns True if the value is null, undefined, or void, otherwise false.
*/
export function isNone<T>(
value: T | null | undefined | void
): value is null | undefined | void {
return value == null;
}
/**
* Checks if a string is numeric.
*
* @param value - The string to check.
* @returns True if the string is numeric, otherwise false.
*/
export function isNumeric(value: string): boolean {
return /-?\d+$/.test(value);
}
/**
* Generates a SHA-1 hash of the given text.
*
* @param text - The text to hash.
* @returns The SHA-1 hash of the text.
*/
export const hash = (text: string) => sha1.sha1(text);
/**
* Executes an array of functions and returns the first result that satisfies the predicate.
*
* @param functions - The array of functions to execute.
* @param predicate - The predicate to test the results. Defaults to checking if the result is not null.
* @returns The first result that satisfies the predicate, or undefined if no result satisfies the predicate.
*/
export async function firstFrom<T>(
functions: Array<() => T | Promise<T>>,
predicate: (result: T) => boolean = result => result != null
): Promise<T | undefined> {
for (const fn of functions) {
const result = await fn();
if (predicate(result)) {
return result;
}
}
return undefined;
}
/**
* Lazily executes an array of functions and yields their results.
*
* @param functions - The array of functions to execute.
* @returns A generator yielding the results of the functions.
*/
function* lazyExecutor<T>(functions: Array<() => T>): Generator<T> {
for (const fn of functions) {
yield fn();
}
}

View File

@@ -1,5 +1,5 @@
import { workspace } from 'vscode';
import { createDailyNoteIfNotExists, getDailyNotePath } from './dated-notes';
import { createDailyNoteIfNotExists, getDailyNoteUri } from './dated-notes';
import { isWindows } from './core/common/platform';
import {
cleanWorkspace,
@@ -10,8 +10,9 @@ import {
withModifiedFoamConfiguration,
} from './test/test-utils-vscode';
import { fromVsCodeUri } from './utils/vsc-utils';
import { URI } from './core/model/uri';
describe('getDailyNotePath', () => {
describe('getDailyNoteUri', () => {
const date = new Date('2021-02-07T00:00:00Z');
const year = date.getFullYear();
const month = date.getMonth() + 1;
@@ -21,12 +22,12 @@ describe('getDailyNotePath', () => {
test('Adds the root directory to relative directories', async () => {
const config = 'journal';
const expectedPath = fromVsCodeUri(
const expectedUri = fromVsCodeUri(
workspace.workspaceFolders[0].uri
).joinPath(config, `${isoDate}.md`);
await withModifiedFoamConfiguration('openDailyNote.directory', config, () =>
expect(getDailyNotePath(date).toFsPath()).toEqual(expectedPath.toFsPath())
expect(getDailyNoteUri(date)).toEqual(expectedUri)
);
});
@@ -39,7 +40,7 @@ describe('getDailyNotePath', () => {
: `${config}/${isoDate}.md`;
await withModifiedFoamConfiguration('openDailyNote.directory', config, () =>
expect(getDailyNotePath(date).toFsPath()).toMatch(expectedPath)
expect(getDailyNoteUri(date).toFsPath()).toMatch(expectedPath)
);
});
});
@@ -54,7 +55,7 @@ describe('Daily note template', () => {
['.foam', 'templates', 'daily-note.md']
);
const uri = getDailyNotePath(targetDate);
const uri = getDailyNoteUri(targetDate);
await createDailyNoteIfNotExists(targetDate);

View File

@@ -1,3 +1,4 @@
import { joinPath } from './core/utils/path';
import dateFormat from 'dateformat';
import { URI } from './core/model/uri';
import { NoteFactory } from './services/templates';
@@ -32,17 +33,13 @@ export async function openDailyNoteFor(date?: Date) {
* This function first checks the `foam.openDailyNote.directory` configuration string,
* defaulting to the current directory.
*
* In the case that the directory path is not absolute,
* the resulting path will start on the current workspace top-level.
*
* @param date A given date to be formatted as filename.
* @returns The path to the daily note file.
* @returns The URI to the daily note file.
*/
export function getDailyNotePath(date: Date): URI {
export function getDailyNoteUri(date: Date): URI {
const folder = getFoamVsCodeConfig<string>('openDailyNote.directory') ?? '.';
const dailyNoteDirectory = asAbsoluteWorkspaceUri(URI.file(folder));
const dailyNoteFilename = getDailyNoteFileName(date);
return dailyNoteDirectory.joinPath(dailyNoteFilename);
return asAbsoluteWorkspaceUri(joinPath(folder, dailyNoteFilename));
}
/**
@@ -76,20 +73,20 @@ export function getDailyNoteFileName(date: Date): string {
* @returns Whether the file was created.
*/
export async function createDailyNoteIfNotExists(targetDate: Date) {
const pathFromLegacyConfiguration = getDailyNotePath(targetDate);
const uriFromLegacyConfiguration = getDailyNoteUri(targetDate);
const pathFromLegacyConfiguration = uriFromLegacyConfiguration.toFsPath();
const titleFormat: string =
getFoamVsCodeConfig('openDailyNote.titleFormat') ??
getFoamVsCodeConfig('openDailyNote.filenameFormat');
const templateFallbackText = `---
foam_template:
filepath: "${pathFromLegacyConfiguration.toFsPath().replace(/\\/g, '\\\\')}"
---
# ${dateFormat(targetDate, titleFormat, false)}
`;
const templateFallbackText = `# ${dateFormat(
targetDate,
titleFormat,
false
)}\n`;
return await NoteFactory.createFromDailyNoteTemplate(
pathFromLegacyConfiguration,
uriFromLegacyConfiguration,
templateFallbackText,
targetDate
);

View File

@@ -175,11 +175,11 @@ async function convertLinkInCopy(
const resource = fParser.parse(fromVsCodeUri(doc.uri), text);
const basePath = doc.uri.path.split('/').slice(0, -1).join('/');
const fileUri = Uri.file(
`${
const fileUri = doc.uri.with({
path: `${
basePath ? basePath + '/' : ''
}${resource.uri.getName()}.copy${resource.uri.getExtension()}`
);
}${resource.uri.getName()}.copy${resource.uri.getExtension()}`,
});
const encoder = new TextEncoder();
await workspace.fs.writeFile(fileUri, encoder.encode(text));
await window.showTextDocument(fileUri);

View File

@@ -4,7 +4,10 @@ import { removeBrackets, toTitleCase } from './copy-without-brackets';
describe('copy-without-brackets command', () => {
it('should get the input from the active editor selection', async () => {
const { uri } = await createFile('This is my [[test-content]].');
const { uri } = await createFile('This is my [[test-content]].', [
'copy-without-brackets',
'file.md',
]);
const { editor } = await showInEditor(uri);
editor.selection = new Selection(new Position(0, 0), new Position(1, 0));
await commands.executeCommand('foam-vscode.copy-without-brackets');

View File

@@ -1,4 +1,4 @@
import { commands, window } from 'vscode';
import { commands, window, workspace } from 'vscode';
import { URI } from '../../core/model/uri';
import { asAbsoluteWorkspaceUri, readFile } from '../../services/editor';
import {
@@ -135,44 +135,53 @@ describe('create-note command', () => {
});
it('supports various options to deal with relative paths', async () => {
const TEST_FOLDER = 'create-note-tests';
const base = await createFile('relative path tests base file', [
'create-note-tests',
TEST_FOLDER,
'base-file.md',
]);
await closeEditors();
await showInEditor(base.uri);
const target = getUriInWorkspace();
expectSameUri(window.activeTextEditor.document.uri, base.uri);
await commands.executeCommand('foam-vscode.create-note', {
notePath: target.getBasename(),
notePath: 'note-resolved-from-root.md',
text: 'test resolving from root',
onRelativeNotePath: 'resolve-from-root',
});
expectSameUri(
window.activeTextEditor.document.uri,
fromVsCodeUri(workspace.workspaceFolders?.[0].uri).joinPath(
'note-resolved-from-root.md'
)
);
expect(window.activeTextEditor.document.getText()).toEqual(
'test resolving from root'
);
expectSameUri(window.activeTextEditor.document.uri, target);
await closeEditors();
await showInEditor(base.uri);
expectSameUri(window.activeTextEditor.document.uri, base.uri);
await commands.executeCommand('foam-vscode.create-note', {
notePath: target.getBasename(),
notePath: 'note-resolved-from-current-dir.md',
text: 'test resolving from current dir',
onRelativeNotePath: 'resolve-from-current-dir',
});
expectSameUri(
window.activeTextEditor.document.uri,
fromVsCodeUri(workspace.workspaceFolders?.[0].uri).joinPath(
TEST_FOLDER,
'note-resolved-from-current-dir.md'
)
);
expect(window.activeTextEditor.document.getText()).toEqual(
'test resolving from current dir'
);
expect(fromVsCodeUri(window.activeTextEditor.document.uri).path).toEqual(
fromVsCodeUri(window.activeTextEditor.document.uri)
.getDirectory()
.joinPath(target.getBasename()).path
);
await closeEditors();
await showInEditor(base.uri);
await commands.executeCommand('foam-vscode.create-note', {
notePath: target.getBasename(),
notePath: 'note-that-should-not-be-created.md',
text: 'test cancelling',
onRelativeNotePath: 'cancel',
});
@@ -184,13 +193,13 @@ describe('create-note command', () => {
.spyOn(window, 'showInputBox')
.mockImplementationOnce(jest.fn(() => Promise.resolve(undefined)));
await commands.executeCommand('foam-vscode.create-note', {
notePath: target.getBasename(),
notePath: 'ask-me-about-it.md',
text: 'test asking',
onRelativeNotePath: 'ask',
});
expect(spy).toHaveBeenCalled();
await deleteFile(base);
// await deleteFile(base);
});
});

View File

@@ -93,7 +93,13 @@ export async function createNote(args: CreateNoteArgs, foam: Foam) {
resolver.define('FOAM_TITLE', args.title);
}
const text = args.text ?? DEFAULT_NEW_NOTE_TEXT;
const noteUri = args.notePath && URI.file(args.notePath);
const schemaSource = vscode.workspace.workspaceFolders[0].uri;
const noteUri =
args.notePath &&
new URI({
scheme: schemaSource.scheme,
path: args.notePath,
});
let templateUri: URI;
if (args.askForTemplate) {
const selectedTemplate = await askUserForTemplate();
@@ -104,7 +110,7 @@ export async function createNote(args: CreateNoteArgs, foam: Foam) {
}
} else {
templateUri = args.templatePath
? asAbsoluteWorkspaceUri(URI.file(args.templatePath))
? asAbsoluteWorkspaceUri(args.templatePath)
: getDefaultTemplateUri();
}
@@ -117,7 +123,7 @@ export async function createNote(args: CreateNoteArgs, foam: Foam) {
args.onFileExists
)
: await NoteFactory.createNote(
noteUri ?? (await getPathFromTitle(resolver)),
noteUri ?? (await getPathFromTitle(templateUri.scheme, resolver)),
text,
resolver,
args.onFileExists,

View File

@@ -123,7 +123,7 @@ export class SectionCompletionProvider
const item = new ResourceCompletionItem(
b.label,
vscode.CompletionItemKind.Text,
resource.uri.withFragment(b.label)
resource.uri.with({ fragment: b.label })
);
item.sortText = String(b.range.start.line).padStart(5, '0');
item.range = replacementRange;

View File

@@ -18,23 +18,27 @@ describe('Editor utils', () => {
describe('getCurrentEditorDirectory', () => {
it('should return the directory of the active text editor', async () => {
const file = await createFile('this is the file content.');
const file = await createFile('this is the file content.', [
'editor-utils',
'file.md',
]);
await showInEditor(file.uri);
expect(getCurrentEditorDirectory()).toEqual(file.uri.getDirectory());
});
it('should return the directory of the workspace folder if no editor is open', async () => {
it('should throw if no editor is open', async () => {
await closeEditors();
expect(getCurrentEditorDirectory()).toEqual(
fromVsCodeUri(workspace.workspaceFolders[0].uri)
);
expect(() => getCurrentEditorDirectory()).toThrow();
});
});
describe('replaceSelection', () => {
it('should replace the selection in the active editor', async () => {
const fileA = await createFile('This is the file A');
const fileA = await createFile('This is the file A', [
'replace-selection',
'file.md',
]);
const doc = await showInEditor(fileA.uri);
const selection = new Selection(0, 5, 0, 7); // 'is'

View File

@@ -18,6 +18,7 @@ import { getExcerpt, stripFrontMatter, stripImages } from '../core/utils/md';
import { isSome } from '../core/utils/core';
import { fromVsCodeUri, toVsCodeUri } from '../utils/vsc-utils';
import { asAbsoluteUri, URI } from '../core/model/uri';
import { getFoamVsCodeConfig } from './config';
import {
AlwaysIncludeMatcher,
FileListBasedMatcher,
@@ -52,14 +53,27 @@ export function formatMarkdownTooltip(content: string): MarkdownString {
return md;
}
export const mdDocSelector = [
{ language: 'markdown', scheme: 'file' },
{ language: 'markdown', scheme: 'vscode-vfs' },
{ language: 'markdown', scheme: 'untitled' },
];
// Generate the document selector dynamically
export const mdDocSelector = getFoamVsCodeConfig<string[]>(
'supportedLanguages',
['markdown']
).flatMap(lang => [
{ language: lang, scheme: 'file' }, // Local files
{ language: lang, scheme: 'vscode-vfs' }, // Remote files
{ language: lang, scheme: 'untitled' }, // Untitled files
]);
export function isMdEditor(editor: TextEditor) {
return editor && editor.document && editor.document.languageId === 'markdown';
// Check if the editor's document is a supported language
export function isMdEditor(editor: TextEditor): boolean {
const supportedLanguages = getFoamVsCodeConfig<string[]>(
'supportedLanguages',
['markdown']
);
return (
editor &&
editor.document &&
supportedLanguages.includes(editor.document.languageId)
);
}
export function findSelectionContent(): SelectionInfo | undefined {
@@ -135,12 +149,10 @@ export function getEditorEOL(): string {
/**
* Returns the directory of the file currently open in the editor.
* If no file is open in the editor it will return the first folder
* in the workspace.
* If both aren't available it will throw.
* If no file is open in the editor it will throw.
*
* @returns URI
* @throws Error if no file is open in editor AND no workspace folder defined
* @throws Error if no file is open in editor
*/
export function getCurrentEditorDirectory(): URI {
const uri = window.activeTextEditor?.document?.uri;
@@ -149,11 +161,7 @@ export function getCurrentEditorDirectory(): URI {
return fromVsCodeUri(uri).getDirectory();
}
if (workspace.workspaceFolders.length > 0) {
return fromVsCodeUri(workspace.workspaceFolders[0].uri);
}
throw new Error('A file must be open in editor, or workspace folder needed');
throw new Error('No editor open');
}
export async function fileExists(uri: URI): Promise<boolean> {
@@ -180,17 +188,17 @@ export function deleteFile(uri: URI) {
/**
* Turns a relative URI into an absolute URI for the given workspace.
* @param uri the uri to evaluate
* @param uriOrPath the uri or path to evaluate
* @returns an absolute uri
*/
export function asAbsoluteWorkspaceUri(uri: URI): URI {
export function asAbsoluteWorkspaceUri(uriOrPath: URI | string): URI {
if (workspace.workspaceFolders === undefined) {
throw new Error('An open folder or workspace is required');
}
const folders = workspace.workspaceFolders.map(folder =>
fromVsCodeUri(folder.uri)
);
const res = asAbsoluteUri(uri, folders);
const res = asAbsoluteUri(uriOrPath, folders);
return res;
}

View File

@@ -24,7 +24,7 @@ import {
import { Resolver } from './variable-resolver';
import dateFormat from 'dateformat';
import { getFoamVsCodeConfig } from './config';
import { isNone } from '../core/utils';
import { firstFrom, isNone } from '../core/utils';
/**
* The templates directory
@@ -233,7 +233,7 @@ const createFnForOnRelativePathStrategy =
const newProposedPath = await askUserForFilepathConfirmation(
existingFile
);
return newProposedPath && URI.file(newProposedPath);
return newProposedPath && existingFile.with({ path: newProposedPath });
}
}
};
@@ -257,7 +257,7 @@ const createFnForOnFileExistsStrategy =
const newProposedPath = await askUserForFilepathConfirmation(
existingFile
);
return newProposedPath && URI.file(newProposedPath);
return newProposedPath && existingFile.with({ path: newProposedPath });
}
}
};
@@ -348,15 +348,16 @@ export const NoteFactory = {
resolver
);
let newFilePath = template.metadata.has('filepath')
? URI.file(template.metadata.get('filepath'))
: filepathFallbackURI;
const pathSources = [
() =>
template.metadata.has('filepath')
? asAbsoluteWorkspaceUri(template.metadata.get('filepath'))
: null,
() => filepathFallbackURI,
() => getPathFromTitle(templateUri.scheme, resolver),
];
if (isNone(newFilePath)) {
newFilePath = await getPathFromTitle(resolver);
} else if (!newFilePath.path.startsWith('./')) {
newFilePath = asAbsoluteWorkspaceUri(newFilePath);
}
const newFilePath = await firstFrom(pathSources);
return NoteFactory.createNote(
newFilePath,
@@ -443,7 +444,7 @@ export const createTemplate = async (): Promise<void> => {
return;
}
const filenameURI = URI.file(filename);
const filenameURI = defaultTemplate.with({ path: filename });
await workspace.fs.writeFile(
toVsCodeUri(filenameURI),
new TextEncoder().encode(TEMPLATE_CONTENT)
@@ -475,7 +476,7 @@ async function askUserForFilepathConfirmation(
});
}
export const getPathFromTitle = async (resolver: Resolver) => {
export const getPathFromTitle = async (scheme: string, resolver: Resolver) => {
const defaultName = await resolver.resolveFromName('FOAM_TITLE_SAFE');
return URI.file(`${defaultName}.md`);
return new URI({ scheme, path: `${defaultName}.md` });
};

View File

@@ -5,7 +5,7 @@
👀*This is an early stage project under rapid development. For updates join the [Foam community Discord](https://foambubble.github.io/join-discord/g)! 💬*
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-121-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-123-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
[![Visual Studio Marketplace Installs](https://img.shields.io/visual-studio-marketplace/i/foam.foam-vscode?label=VS%20Code%20Installs)](https://marketplace.visualstudio.com/items?itemName=foam.foam-vscode)
@@ -365,6 +365,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<tr>
<td align="center" valign="top" width="14.28%"><a href="http://www.hegghammer.com"><img src="https://avatars.githubusercontent.com/u/64712218?v=4?s=60" width="60px;" alt="Thomas Hegghammer"/><br /><sub><b>Thomas Hegghammer</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=Hegghammer" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PiotrAleksander"><img src="https://avatars.githubusercontent.com/u/6314591?v=4?s=60" width="60px;" alt="Piotr Mrzygłosz"/><br /><sub><b>Piotr Mrzygłosz</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=PiotrAleksander" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://schaver.com/"><img src="https://avatars.githubusercontent.com/u/7584?v=4?s=60" width="60px;" alt="Mark Schaver"/><br /><sub><b>Mark Schaver</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=markschaver" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/n8layman"><img src="https://avatars.githubusercontent.com/u/25353944?v=4?s=60" width="60px;" alt="Nathan Layman"/><br /><sub><b>Nathan Layman</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=n8layman" title="Code">💻</a></td>
</tr>
</tbody>
</table>

112
yarn.lock
View File

@@ -3077,7 +3077,7 @@ ansi-styles@^6.1.0:
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
anymatch@^3.0.3:
anymatch@^3.0.3, anymatch@~3.1.2:
version "3.1.3"
resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz"
integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
@@ -3478,6 +3478,11 @@ bin-links@^4.0.1:
read-cmd-shim "^4.0.0"
write-file-atomic "^5.0.0"
binary-extensions@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
binary@~0.3.0:
version "0.3.0"
resolved "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz"
@@ -3522,6 +3527,13 @@ braces@^3.0.2:
dependencies:
fill-range "^7.0.1"
braces@~3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
fill-range "^7.1.1"
browser-process-hrtime@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz"
@@ -3767,6 +3779,21 @@ chardet@^0.7.0:
resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
chokidar@^3.5.2:
version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.6.0"
optionalDependencies:
fsevents "~2.3.2"
chownr@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz"
@@ -4236,6 +4263,13 @@ debug@^3.1.0, debug@^3.2.7:
dependencies:
ms "^2.1.1"
debug@^4:
version "4.3.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
dependencies:
ms "^2.1.3"
decamelize-keys@^1.1.0:
version "1.1.1"
resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz"
@@ -5303,6 +5337,13 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"
find-cache-dir@^3.3.2:
version "3.3.2"
resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz"
@@ -5651,7 +5692,7 @@ github-slugger@^1.4.0:
resolved "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz"
integrity sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==
glob-parent@5.1.2, glob-parent@^5.1.2:
glob-parent@5.1.2, glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
@@ -6110,6 +6151,11 @@ ieee754@^1.1.13:
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
ignore-by-default@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
ignore-walk@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz"
@@ -6326,6 +6372,13 @@ is-bigint@^1.0.1:
dependencies:
has-bigints "^1.0.1"
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
is-boolean-object@^1.1.0:
version "1.1.2"
resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz"
@@ -6419,7 +6472,7 @@ is-generator-function@^1.0.7:
dependencies:
has-tostringtag "^1.0.0"
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
version "4.0.3"
resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
@@ -8486,7 +8539,7 @@ ms@2.1.2:
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@^2.0.0, ms@^2.1.1:
ms@^2.0.0, ms@^2.1.1, ms@^2.1.3:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -8596,6 +8649,22 @@ node-releases@^2.0.8:
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz"
integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
nodemon@^3.1.7:
version "3.1.7"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.7.tgz#07cb1f455f8bece6a499e0d72b5e029485521a54"
integrity sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==
dependencies:
chokidar "^3.5.2"
debug "^4"
ignore-by-default "^1.0.1"
minimatch "^3.1.2"
pstree.remy "^1.1.8"
semver "^7.5.3"
simple-update-notifier "^2.0.0"
supports-color "^5.5.0"
touch "^3.1.0"
undefsafe "^2.0.5"
nopt@^6.0.0:
version "6.0.0"
resolved "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz"
@@ -8650,7 +8719,7 @@ normalize-package-data@^5.0.0:
semver "^7.3.5"
validate-npm-package-license "^3.0.4"
normalize-path@^3.0.0:
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
@@ -9371,7 +9440,7 @@ picocolors@^1.0.0:
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picomatch@^2.0.4, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1:
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
@@ -9603,6 +9672,11 @@ psl@^1.1.33:
resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz"
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
pstree.remy@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
pump@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz"
@@ -9819,6 +9893,13 @@ readable-stream@^2.0.2:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz"
@@ -10296,6 +10377,13 @@ sigstore@^1.0.0, sigstore@^1.3.0, sigstore@^1.4.0:
"@sigstore/tuf" "^1.0.3"
make-fetch-happen "^11.0.1"
simple-update-notifier@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb"
integrity sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==
dependencies:
semver "^7.5.3"
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz"
@@ -10657,7 +10745,7 @@ strong-log-transformer@2.1.0, strong-log-transformer@^2.1.0:
minimist "^1.2.0"
through "^2.3.4"
supports-color@^5.3.0:
supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
@@ -10903,6 +10991,11 @@ toidentifier@1.0.1:
resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
touch@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694"
integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==
tough-cookie@^4.0.0:
version "4.1.2"
resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz"
@@ -11165,6 +11258,11 @@ unbox-primitive@^1.0.2:
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
undefsafe@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
unherit@^1.0.4:
version "1.1.3"
resolved "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz"