Merge branch 'master' into develop
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "omnisearch",
|
||||
"name": "Omnisearch",
|
||||
"version": "1.16.0",
|
||||
"version": "1.18.1",
|
||||
"minAppVersion": "1.3.0",
|
||||
"description": "A search engine that just works",
|
||||
"author": "Simon Cambier",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "omnisearch",
|
||||
"name": "Omnisearch",
|
||||
"version": "1.16.0",
|
||||
"version": "1.18.1",
|
||||
"minAppVersion": "1.3.0",
|
||||
"description": "A search engine that just works",
|
||||
"author": "Simon Cambier",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "scambier.obsidian-search",
|
||||
"version": "1.16.0",
|
||||
"version": "1.18.1",
|
||||
"description": "A search engine for Obsidian",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
@@ -28,7 +28,7 @@
|
||||
"esbuild-plugin-copy": "1.3.0",
|
||||
"esbuild-svelte": "0.7.1",
|
||||
"jest": "^27.5.1",
|
||||
"obsidian": "latest",
|
||||
"obsidian": "^1.4.11",
|
||||
"prettier": "^2.8.1",
|
||||
"prettier-plugin-svelte": "^2.8.1",
|
||||
"svelte": "^3.54.0",
|
||||
|
||||
2224
pnpm-lock.yaml
generated
2224
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import { Notice } from 'obsidian'
|
||||
import { Notice, TFile } from 'obsidian'
|
||||
import {
|
||||
type DocumentRef,
|
||||
getTextExtractor,
|
||||
@@ -32,8 +32,9 @@ import { settings } from './settings'
|
||||
async function getAndMapIndexedDocument(
|
||||
path: string
|
||||
): Promise<IndexedDocument> {
|
||||
const file = app.vault.getFiles().find(f => f.path === path)
|
||||
const file = app.vault.getAbstractFileByPath(path)
|
||||
if (!file) throw new Error(`Invalid file path: "${path}"`)
|
||||
if (!(file instanceof TFile)) throw new Error(`Not a TFile: "${path}"`)
|
||||
let content: string | null = null
|
||||
|
||||
const extractor = getTextExtractor()
|
||||
@@ -74,7 +75,7 @@ async function getAndMapIndexedDocument(
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] === 'object') {
|
||||
iterate(obj[key])
|
||||
} else if (key === 'markdown') {
|
||||
} else if (key === 'content') {
|
||||
texts.push(obj[key])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import InputSearch from './InputSearch.svelte'
|
||||
import {
|
||||
Action,
|
||||
eventBus,
|
||||
excerptAfter,
|
||||
type ResultNote,
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
} else {
|
||||
// Open in-file modal for active file
|
||||
const view = app.workspace.getActiveViewOfType(MarkdownView)
|
||||
if (view) {
|
||||
if (view?.file) {
|
||||
new OmnisearchInFileModal(app, view.file, searchQuery).open()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ export function isCacheEnabled(): boolean {
|
||||
}
|
||||
|
||||
const separators =
|
||||
/[|\t\n\r= -#%-*,.`\/:;?@[-\]_{}\u00A0\u00A1\u00A7\u00AB\u00B6\u00B7\u00BB\u00BF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C77\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166E\u1680\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2000-\u200A\u2010-\u2029\u202F-\u2043\u2045-\u2051\u2053-\u205F\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4F\u3000-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]/
|
||||
/[|\t\n\r= -#%-*,.`\/<>:;?@[-\]_{}\u00A0\u00A1\u00A7\u00AB\u00B6\u00B7\u00BB\u00BF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C77\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166E\u1680\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2000-\u200A\u2010-\u2029\u202F-\u2043\u2045-\u2051\u2053-\u205F\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4F\u3000-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]/
|
||||
.toString()
|
||||
.slice(1, -1)
|
||||
export const SPACE_OR_PUNCTUATION_UNIQUE = new RegExp(`${separators}`, 'u')
|
||||
|
||||
15
src/main.ts
15
src/main.ts
@@ -28,10 +28,19 @@ import { cacheManager } from './cache-manager'
|
||||
export default class OmnisearchPlugin extends Plugin {
|
||||
private ribbonButton?: HTMLElement
|
||||
|
||||
// FIXME: fix the type
|
||||
public apiHttpServer: null | any = null
|
||||
|
||||
async onload(): Promise<void> {
|
||||
await loadSettings(this)
|
||||
this.addSettingTab(new SettingsTab(this))
|
||||
|
||||
if (!Platform.isMobile) {
|
||||
import('./tools/api-server').then(m =>
|
||||
this.apiHttpServer = m.getServer()
|
||||
)
|
||||
}
|
||||
|
||||
if (isPluginDisabled()) {
|
||||
console.log('Omnisearch - Plugin disabled')
|
||||
return
|
||||
@@ -112,6 +121,10 @@ export default class OmnisearchPlugin extends Plugin {
|
||||
|
||||
this.executeFirstLaunchTasks()
|
||||
await this.populateIndex()
|
||||
|
||||
if (this.apiHttpServer && settings.httpApiEnabled) {
|
||||
this.apiHttpServer.listen(settings.httpApiPort)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -137,6 +150,7 @@ export default class OmnisearchPlugin extends Plugin {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
await database.clearCache()
|
||||
}
|
||||
this.apiHttpServer.close()
|
||||
}
|
||||
|
||||
addRibbonButton(): void {
|
||||
@@ -259,4 +273,3 @@ function registerAPI(plugin: OmnisearchPlugin): void {
|
||||
// Deprecated
|
||||
;(app as any).plugins.plugins.omnisearch.api = api
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,10 @@ export class Query {
|
||||
return this.getTags().map(o => o.replace(/^#/, ''))
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns An array of strings that are in quotes
|
||||
*/
|
||||
public getExactTerms(): string[] {
|
||||
return [
|
||||
...new Set(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
Notice,
|
||||
Platform,
|
||||
Plugin,
|
||||
PluginSettingTab,
|
||||
Setting,
|
||||
@@ -58,6 +59,8 @@ export interface OmnisearchSettings extends WeightingSettings {
|
||||
verboseLogging: boolean
|
||||
vimLikeNavigationShortcut: boolean
|
||||
fuzziness: '0' | '1' | '2'
|
||||
httpApiEnabled: boolean
|
||||
httpApiPort: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,7 +287,9 @@ export class SettingsTab extends PluginSettingTab {
|
||||
'Navigate down the results with Ctrl/⌘ + J/N, or navigate up with Ctrl/⌘ + K/P'
|
||||
)
|
||||
.addToggle(toggle =>
|
||||
toggle.setValue(settings.vimLikeNavigationShortcut).onChange(async v => {
|
||||
toggle
|
||||
.setValue(settings.vimLikeNavigationShortcut)
|
||||
.onChange(async v => {
|
||||
settings.vimLikeNavigationShortcut = v
|
||||
await saveSettings(this.plugin)
|
||||
})
|
||||
@@ -454,7 +459,54 @@ export class SettingsTab extends PluginSettingTab {
|
||||
})
|
||||
)
|
||||
|
||||
//#endregion Debugginh
|
||||
//#endregion Debugging
|
||||
|
||||
//#region HTTP Server
|
||||
|
||||
if (!Platform.isMobile) {
|
||||
const httpServerDesc = new DocumentFragment()
|
||||
httpServerDesc.createSpan({}, span => {
|
||||
span.innerHTML = `Omnisearch can be used through a simple HTTP server (<a href="https://publish.obsidian.md/omnisearch/Public+API+%26+URL+Scheme#HTTP+Server">more information</a>).`
|
||||
})
|
||||
new Setting(containerEl)
|
||||
.setName('API Access Through HTTP')
|
||||
.setHeading()
|
||||
.setDesc(httpServerDesc)
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Enable the HTTP server')
|
||||
.addToggle(toggle =>
|
||||
toggle.setValue(settings.httpApiEnabled).onChange(async v => {
|
||||
settings.httpApiEnabled = v
|
||||
if (v) {
|
||||
this.plugin.apiHttpServer.listen(settings.httpApiPort)
|
||||
} else {
|
||||
this.plugin.apiHttpServer.close()
|
||||
}
|
||||
await saveSettings(this.plugin)
|
||||
})
|
||||
)
|
||||
|
||||
new Setting(containerEl).setName('HTTP Port').addText(component => {
|
||||
component
|
||||
.setValue(settings.httpApiPort)
|
||||
.setPlaceholder('51361')
|
||||
.onChange(async v => {
|
||||
if (parseInt(v) > 65535) {
|
||||
v = settings.httpApiPort
|
||||
component.setValue(settings.httpApiPort)
|
||||
}
|
||||
settings.httpApiPort = v
|
||||
if (settings.httpApiEnabled) {
|
||||
this.plugin.apiHttpServer.close()
|
||||
this.plugin.apiHttpServer.listen(settings.httpApiPort)
|
||||
}
|
||||
await saveSettings(this.plugin)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//#endregion HTTP Server
|
||||
|
||||
//#region Danger Zone
|
||||
new Setting(containerEl).setName('Danger Zone').setHeading()
|
||||
@@ -479,6 +531,7 @@ export class SettingsTab extends PluginSettingTab {
|
||||
})
|
||||
)
|
||||
|
||||
// Disable Omnisearch
|
||||
const disableDesc = new DocumentFragment()
|
||||
disableDesc.createSpan({}, span => {
|
||||
span.innerHTML = `Disable Omnisearch on this device only.<br>
|
||||
@@ -498,6 +551,7 @@ export class SettingsTab extends PluginSettingTab {
|
||||
})
|
||||
)
|
||||
|
||||
// Clear cache data
|
||||
if (isCacheEnabled()) {
|
||||
const resetCacheDesc = new DocumentFragment()
|
||||
resetCacheDesc.createSpan({}, span => {
|
||||
@@ -522,7 +576,7 @@ export class SettingsTab extends PluginSettingTab {
|
||||
cb.setLimits(1, 5, 0.1)
|
||||
.setValue(settings[key])
|
||||
.setDynamicTooltip()
|
||||
.onChange(async (v) => {
|
||||
.onChange(async v => {
|
||||
settings[key] = v
|
||||
await saveSettings(this.plugin)
|
||||
})
|
||||
@@ -557,6 +611,9 @@ export const DEFAULT_SETTINGS: OmnisearchSettings = {
|
||||
weightH3: 1.1,
|
||||
weightUnmarkedTags: 1.1,
|
||||
|
||||
httpApiEnabled: false,
|
||||
httpApiPort: '51361',
|
||||
|
||||
welcomeMessage: '',
|
||||
verboseLogging: false,
|
||||
} as const
|
||||
|
||||
70
src/tools/api-server.ts
Normal file
70
src/tools/api-server.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import * as http from 'http'
|
||||
import * as url from 'url'
|
||||
import api from './api'
|
||||
import { Notice } from 'obsidian'
|
||||
import { saveSettings, settings } from 'src/settings'
|
||||
|
||||
export function getServer() {
|
||||
const server = http.createServer(async function (req, res) {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Methods',
|
||||
'GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE'
|
||||
)
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Headers',
|
||||
'Access-Control-Allow-Headers, Origin, Authorization,Accept,x-client-id, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, hypothesis-client-version'
|
||||
)
|
||||
res.setHeader('Access-Control-Allow-Credentials', 'true')
|
||||
|
||||
try {
|
||||
if (req.url) {
|
||||
// parse URL
|
||||
const parsedUrl = url.parse(req.url, true)
|
||||
if (parsedUrl.pathname === '/search') {
|
||||
const q = parsedUrl.query.q as string
|
||||
const results = await api.search(q)
|
||||
res.statusCode = 200
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.end(JSON.stringify(results))
|
||||
} else {
|
||||
res.end()
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
res.statusCode = 500
|
||||
res.end(e)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
listen(port: string) {
|
||||
console.log(`Omnisearch - Starting HTTP server on port ${port}`)
|
||||
server.listen(
|
||||
{
|
||||
port: parseInt(port),
|
||||
host: 'localhost',
|
||||
},
|
||||
() => {
|
||||
console.log(`Omnisearch - Started HTTP server on port ${port}`)
|
||||
new Notice(`Omnisearch - Started HTTP server on port ${port}`)
|
||||
}
|
||||
)
|
||||
|
||||
server.on('error', e => {
|
||||
console.error(e)
|
||||
new Notice(
|
||||
`Omnisearch - Cannot start HTTP server on ${port}. See console for more details.`
|
||||
)
|
||||
})
|
||||
},
|
||||
close() {
|
||||
server.close()
|
||||
console.log(`Omnisearch - Terminated HTTP server`)
|
||||
new Notice(`Omnisearch - Terminated HTTP server`)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default getServer
|
||||
export type StaticServer = ReturnType<typeof getServer>
|
||||
@@ -6,6 +6,7 @@ import { refreshIndex } from '../notes-index'
|
||||
|
||||
type ResultNoteApi = {
|
||||
score: number
|
||||
vault: string
|
||||
path: string
|
||||
basename: string
|
||||
foundWords: string[]
|
||||
@@ -33,6 +34,7 @@ function mapResults(results: ResultNote[]): ResultNoteApi[] {
|
||||
|
||||
const res: ResultNoteApi = {
|
||||
score,
|
||||
vault: app.vault.getName(),
|
||||
path,
|
||||
basename,
|
||||
foundWords,
|
||||
|
||||
@@ -10,9 +10,10 @@ import {
|
||||
excerptBefore,
|
||||
} from 'src/globals'
|
||||
import { settings } from 'src/settings'
|
||||
import { escapeRegex, warnDebug } from './utils'
|
||||
import { warnDebug } from './utils'
|
||||
import type { Query } from 'src/search/query'
|
||||
import { Notice } from 'obsidian'
|
||||
import { escapeRegExp } from 'lodash-es'
|
||||
|
||||
export function highlighterGroups(_substring: string, ...args: any[]) {
|
||||
// args[0] is the single char preceding args[1], which is the word we want to highlight
|
||||
@@ -21,39 +22,35 @@ export function highlighterGroups(_substring: string, ...args: any[]) {
|
||||
return '<no content>'
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the matches in the text with a <span> element and a highlight class
|
||||
* @param text
|
||||
* @param matches
|
||||
* @returns The html string with the matches highlighted
|
||||
*/
|
||||
export function highlightText(text: string, matches: SearchMatch[]): string {
|
||||
matches.forEach(matchInfo => {
|
||||
const matchRegex = new RegExp(`\\b${matchInfo.match}\\b`, 'giu')
|
||||
const matchOffsets = []
|
||||
|
||||
let match
|
||||
while ((match = matchRegex.exec(text)) !== null) {
|
||||
matchOffsets.push({ index: match.index, text: match[0] })
|
||||
try {
|
||||
return text.replace(
|
||||
new RegExp(
|
||||
matches
|
||||
.map(matchInfo => `\\b${escapeRegExp(matchInfo.match)}\\b`)
|
||||
.join('|'),
|
||||
'giu'
|
||||
),
|
||||
match => {
|
||||
const matchInfo = matches.find(info =>
|
||||
match.match(new RegExp(`\\b${escapeRegExp(info.match)}\\b`, 'giu'))
|
||||
)
|
||||
if (matchInfo) {
|
||||
return `<span class="${highlightClass}">${match}</span>`
|
||||
}
|
||||
|
||||
if (!matchOffsets.length) {
|
||||
return match
|
||||
}
|
||||
)
|
||||
} catch (e) {
|
||||
console.error('Omnisearch - Error in highlightText()', e)
|
||||
return text
|
||||
}
|
||||
|
||||
const closestMatch = matchOffsets.reduce((prev, curr) => {
|
||||
return Math.abs(curr.index - matchInfo.offset) <
|
||||
Math.abs(prev.index - matchInfo.offset)
|
||||
? curr
|
||||
: prev
|
||||
})
|
||||
|
||||
if (matchOffsets.includes(closestMatch)) {
|
||||
const originalMatch = closestMatch.text
|
||||
text =
|
||||
text.substring(0, closestMatch.index) +
|
||||
`<span class="${highlightClass}">` +
|
||||
originalMatch +
|
||||
'</span>' +
|
||||
text.substring(closestMatch.index + originalMatch.length)
|
||||
}
|
||||
})
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
export function escapeHTML(html: string): string {
|
||||
@@ -94,10 +91,9 @@ export function stringsToRegex(strings: string[]): RegExp {
|
||||
? `^|${SPACE_OR_PUNCTUATION_UNIQUE.source}|\-|[A-Z]`
|
||||
: `^|${SPACE_OR_PUNCTUATION_UNIQUE.source}|\-`) +
|
||||
')' +
|
||||
`(${strings.map(s => escapeRegex(s)).join('|')})`
|
||||
`(${strings.map(s => escapeRegExp(s)).join('|')})`
|
||||
|
||||
const reg = new RegExp(`${joined}`, 'gu')
|
||||
return reg
|
||||
return new RegExp(`${joined}`, 'gu')
|
||||
}
|
||||
|
||||
export function getMatches(
|
||||
@@ -122,8 +118,8 @@ export function getMatches(
|
||||
}
|
||||
}
|
||||
|
||||
// If the query can be found "as is" in the text, put this match first
|
||||
if (query) {
|
||||
// If the query is more than 1 token and can be found "as is" in the text, put this match first
|
||||
if (query && query.query.text.length > 1) {
|
||||
const best = text.indexOf(query.segmentsToStr())
|
||||
if (best > -1 && matches.find(m => m.offset === best)) {
|
||||
matches = matches.filter(m => m.offset !== best)
|
||||
|
||||
@@ -25,12 +25,6 @@ export function wait(ms: number): Promise<void> {
|
||||
})
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/3561711
|
||||
// but we enclose special chars in brackets to avoid them being interpreted as regex
|
||||
export function escapeRegex(str: string): string {
|
||||
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, '[$&]')
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the positions of all occurences of `val` inside of `text`
|
||||
* https://stackoverflow.com/a/58828841
|
||||
@@ -180,7 +174,7 @@ export function isFileCanvas(path: string): boolean {
|
||||
}
|
||||
|
||||
export function isFileFromDataloomPlugin(path: string): boolean {
|
||||
return path.endsWith('.loom') || path.endsWith('.dashboard')
|
||||
return path.endsWith('.loom')
|
||||
}
|
||||
|
||||
export function getExtension(path: string): string {
|
||||
|
||||
@@ -115,5 +115,9 @@
|
||||
"1.15.0": "1.0.0",
|
||||
"1.15.1": "1.3.0",
|
||||
"1.16.0-beta.1": "1.3.0",
|
||||
"1.16.0": "1.3.0"
|
||||
"1.16.0": "1.3.0",
|
||||
"1.17.0": "1.3.0",
|
||||
"1.17.1": "1.3.0",
|
||||
"1.18.0": "1.3.0",
|
||||
"1.18.1": "1.3.0"
|
||||
}
|
||||
Reference in New Issue
Block a user