@sailshq/language-server 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SailsParser.js +403 -0
- package/completions/actions-completion.js +36 -0
- package/completions/data-types-completion.js +38 -0
- package/completions/inertia-pages-completion.js +33 -0
- package/completions/input-props-completion.js +56 -0
- package/completions/model-attribute-props-completion.js +53 -0
- package/completions/model-attributes-completion.js +102 -0
- package/completions/model-methods-completion.js +61 -0
- package/completions/models-completion.js +52 -0
- package/completions/policies-completion.js +32 -0
- package/completions/views-completion.js +35 -0
- package/go-to-definitions/go-to-action.js +26 -49
- package/go-to-definitions/go-to-helper.js +33 -33
- package/go-to-definitions/go-to-model.js +39 -0
- package/go-to-definitions/go-to-page.js +38 -0
- package/go-to-definitions/go-to-policy.js +23 -72
- package/go-to-definitions/go-to-view.js +28 -55
- package/index.js +95 -20
- package/package.json +1 -1
- package/validators/validate-action-exist.js +28 -51
- package/validators/validate-data-type.js +34 -0
- package/validators/validate-document.js +21 -5
- package/validators/validate-model-attribute-exist.js +128 -0
- package/validators/validate-page-exist.js +42 -0
- package/validators/validate-policy-exist.js +45 -0
- package/completions/sails-completions.js +0 -63
- package/go-to-definitions/go-to-inertia-page.js +0 -53
- package/helpers/find-fn-line.js +0 -21
- package/helpers/find-project-root.js +0 -18
- package/helpers/find-sails.js +0 -12
- package/helpers/load-sails.js +0 -38
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
const lsp = require('vscode-languageserver/node')
|
|
2
|
-
const loadSails = require('../helpers/load-sails')
|
|
3
|
-
|
|
4
|
-
module.exports = async function sailsCompletions(document, position) {
|
|
5
|
-
const text = document.getText()
|
|
6
|
-
const offset = document.offsetAt(position)
|
|
7
|
-
const line = text.substring(0, offset).split('\n').pop()
|
|
8
|
-
|
|
9
|
-
const match = line.match(/sails((?:\.[a-zA-Z_$][0-9a-zA-Z_$]*)*)\.$/)
|
|
10
|
-
if (match) {
|
|
11
|
-
try {
|
|
12
|
-
return await loadSails(document.uri, (sailsApp) => {
|
|
13
|
-
const path = match[1].split('.').filter(Boolean)
|
|
14
|
-
return getNestedCompletions(sailsApp, path)
|
|
15
|
-
})
|
|
16
|
-
} catch (error) {
|
|
17
|
-
return []
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return null
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function getNestedCompletions(obj, path) {
|
|
25
|
-
let current = obj
|
|
26
|
-
for (const key of path) {
|
|
27
|
-
if (current && typeof current === 'object' && key in current) {
|
|
28
|
-
current = current[key]
|
|
29
|
-
} else {
|
|
30
|
-
return []
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (typeof current !== 'object' || current === null) {
|
|
35
|
-
return []
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const completions = Object.keys(current).map((key) => {
|
|
39
|
-
const value = current[key]
|
|
40
|
-
let kind = lsp.CompletionItemKind.Property
|
|
41
|
-
let detail = 'Property'
|
|
42
|
-
|
|
43
|
-
if (typeof value === 'function') {
|
|
44
|
-
kind = lsp.CompletionItemKind.Method
|
|
45
|
-
detail = 'Method'
|
|
46
|
-
} else if (typeof value === 'object' && value !== null) {
|
|
47
|
-
detail = 'Object'
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
label: key,
|
|
52
|
-
kind: kind,
|
|
53
|
-
detail: detail,
|
|
54
|
-
documentation: `Access to sails${path.length ? '.' + path.join('.') : ''}.${key}`,
|
|
55
|
-
sortText: key.startsWith('_') ? `z${key}` : key // Add this line
|
|
56
|
-
}
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
// Sort the completions
|
|
60
|
-
completions.sort((a, b) => a.sortText.localeCompare(b.sortText))
|
|
61
|
-
|
|
62
|
-
return completions
|
|
63
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
const lsp = require('vscode-languageserver/node')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const fs = require('fs').promises
|
|
4
|
-
const findProjectRoot = require('../helpers/find-project-root')
|
|
5
|
-
|
|
6
|
-
module.exports = async function goToInertiaPage(document, position) {
|
|
7
|
-
const pageInfo = extractPageInfo(document, position)
|
|
8
|
-
|
|
9
|
-
if (!pageInfo) {
|
|
10
|
-
return null
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const projectRoot = await findProjectRoot(document.uri)
|
|
14
|
-
const possibleExtensions = ['.js', '.jsx', '.ts', '.tsx', '.vue', '.svelte'] // Add or remove extensions as needed
|
|
15
|
-
|
|
16
|
-
for (const ext of possibleExtensions) {
|
|
17
|
-
const fullPagePath = path.join(
|
|
18
|
-
projectRoot,
|
|
19
|
-
'assets',
|
|
20
|
-
'js',
|
|
21
|
-
'pages',
|
|
22
|
-
`${pageInfo.page}${ext}`
|
|
23
|
-
)
|
|
24
|
-
try {
|
|
25
|
-
await fs.access(fullPagePath)
|
|
26
|
-
return lsp.Location.create(fullPagePath, lsp.Range.create(0, 0, 0, 0))
|
|
27
|
-
} catch (error) {
|
|
28
|
-
// File doesn't exist with this extension, try the next one
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function extractPageInfo(document, position) {
|
|
36
|
-
const text = document.getText()
|
|
37
|
-
const offset = document.offsetAt(position)
|
|
38
|
-
|
|
39
|
-
// Regular expression to match { page: 'example' } or { page: "example" }
|
|
40
|
-
const regex = /{\s*page\s*:\s*['"]([^'"]+)['"]\s*}/g
|
|
41
|
-
let match
|
|
42
|
-
|
|
43
|
-
while ((match = regex.exec(text)) !== null) {
|
|
44
|
-
const start = match.index
|
|
45
|
-
const end = start + match[0].length
|
|
46
|
-
|
|
47
|
-
if (start <= offset && offset <= end) {
|
|
48
|
-
return { page: match[1] }
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return null
|
|
53
|
-
}
|
package/helpers/find-fn-line.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const fs = require('fs').promises
|
|
2
|
-
const url = require('url')
|
|
3
|
-
|
|
4
|
-
module.exports = async function findFnLine(filePath) {
|
|
5
|
-
try {
|
|
6
|
-
const resolvedPath = filePath.startsWith('file:')
|
|
7
|
-
? url.fileURLToPath(filePath)
|
|
8
|
-
: filePath
|
|
9
|
-
|
|
10
|
-
const content = await fs.readFile(resolvedPath, 'utf8')
|
|
11
|
-
const lines = content.split('\n')
|
|
12
|
-
for (let i = 0; i < lines.length; i++) {
|
|
13
|
-
if (lines[i].includes('fn:')) {
|
|
14
|
-
return i // Return the line number (0-based index)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return 0 // If 'fn:' is not found, return the first line
|
|
18
|
-
} catch (error) {
|
|
19
|
-
return 0 // Return the first line if there's an error
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const url = require('url')
|
|
3
|
-
const fs = require('fs').promises
|
|
4
|
-
|
|
5
|
-
module.exports = async function findProjectRoot(uri) {
|
|
6
|
-
let currentPath = path.dirname(url.fileURLToPath(uri))
|
|
7
|
-
const root = path.parse(currentPath).root
|
|
8
|
-
|
|
9
|
-
while (currentPath !== root) {
|
|
10
|
-
try {
|
|
11
|
-
await fs.access(path.join(currentPath, 'package.json'))
|
|
12
|
-
return currentPath
|
|
13
|
-
} catch (error) {
|
|
14
|
-
currentPath = path.dirname(currentPath)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
throw new Error('Could not find project root')
|
|
18
|
-
}
|
package/helpers/find-sails.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const findProjectRoot = require('./find-project-root')
|
|
4
|
-
|
|
5
|
-
module.exports = async function findSails(workspaceUri) {
|
|
6
|
-
const projectRoot = await findProjectRoot(workspaceUri)
|
|
7
|
-
const sailsPath = path.join(projectRoot, 'node_modules', 'sails')
|
|
8
|
-
if (fs.existsSync(sailsPath)) {
|
|
9
|
-
return { sailsPath, projectRoot }
|
|
10
|
-
}
|
|
11
|
-
throw new Error('Sails not found in node_modules')
|
|
12
|
-
}
|
package/helpers/load-sails.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const findSails = require('./find-sails')
|
|
2
|
-
|
|
3
|
-
module.exports = async function loadSails(workspaceUri, operation) {
|
|
4
|
-
let Sails
|
|
5
|
-
let sailsApp
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
const { sailsPath } = await findSails(workspaceUri)
|
|
9
|
-
Sails = require(sailsPath).constructor
|
|
10
|
-
|
|
11
|
-
sailsApp = await new Promise((resolve, reject) => {
|
|
12
|
-
new Sails().load(
|
|
13
|
-
{
|
|
14
|
-
hooks: { shipwright: false },
|
|
15
|
-
log: { level: 'silent' }
|
|
16
|
-
},
|
|
17
|
-
(err, sails) => {
|
|
18
|
-
if (err) {
|
|
19
|
-
console.error('Failed to load Sails app:', err)
|
|
20
|
-
return reject(err)
|
|
21
|
-
}
|
|
22
|
-
resolve(sails)
|
|
23
|
-
}
|
|
24
|
-
)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
// Execute the operation with the loaded Sails app
|
|
28
|
-
return await operation(sailsApp)
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.error('Error loading or working with Sails app:', error)
|
|
31
|
-
throw error
|
|
32
|
-
} finally {
|
|
33
|
-
// Ensure Sails is lowered even if an error occurred
|
|
34
|
-
if (sailsApp && typeof sailsApp.lower === 'function') {
|
|
35
|
-
await new Promise((resolve) => sailsApp.lower(resolve))
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|